commit e4ca64c640fa3839546d0f226ec31445f1e439c3 Author: cheney Date: Sat Mar 22 20:44:14 2025 +0800 移植 sunpkcs11 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a499c43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store +/.idea/.gitignore +/.idea/encodings.xml +/.idea/misc.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f3e8f77 --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + com.sunyard + JceOnPkcs11 + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + + + \ No newline at end of file diff --git a/src/main/java/com/sunyard/Main.java b/src/main/java/com/sunyard/Main.java new file mode 100644 index 0000000..7d0bcf2 --- /dev/null +++ b/src/main/java/com/sunyard/Main.java @@ -0,0 +1,7 @@ +package com.sunyard; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} \ No newline at end of file diff --git a/src/main/java/com/sunyard/security/pkcs11/Config.java b/src/main/java/com/sunyard/security/pkcs11/Config.java new file mode 100644 index 0000000..759de35 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/Config.java @@ -0,0 +1,1018 @@ +/* + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.*; +import static java.io.StreamTokenizer.*; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import java.security.*; + +import sun.security.action.GetPropertyAction; +import sun.security.util.PropertyExpander; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; +import static com.sunyard.security.pkcs11.wrapper.CK_ATTRIBUTE.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; + +/** + * Configuration container and file parsing. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class Config { + + static final int ERR_HALT = 1; + static final int ERR_IGNORE_ALL = 2; + static final int ERR_IGNORE_LIB = 3; + + // same as allowSingleThreadedModules but controlled via a system property + // and applied to all providers. if set to false, no SunPKCS11 instances + // will accept single threaded modules regardless of the setting in their + // config files. + private static final boolean staticAllowSingleThreadedModules; + + static { + String p = "sun.security.pkcs11.allowSingleThreadedModules"; + String s = AccessController.doPrivileged(new GetPropertyAction(p)); + if ("false".equalsIgnoreCase(s)) { + staticAllowSingleThreadedModules = false; + } else { + staticAllowSingleThreadedModules = true; + } + } + + // temporary storage for configurations + // needed because the SunPKCS11 needs to call the superclass constructor + // in provider before accessing any instance variables + private final static Map configMap = + new HashMap(); + + static Config getConfig(final String name, final InputStream stream) { + Config config = configMap.get(name); + if (config != null) { + return config; + } + try { + config = new Config(name, stream); + configMap.put(name, config); + return config; + } catch (Exception e) { + throw new ProviderException("Error parsing configuration", e); + } + } + + static Config removeConfig(String name) { + return configMap.remove(name); + } + + private final static boolean DEBUG = false; + + private static void debug(Object o) { + if (DEBUG) { + System.out.println(o); + } + } + + // Reader and StringTokenizer used during parsing + private Reader reader; + + private StreamTokenizer st; + + private Set parsedKeywords; + + // name suffix of the provider + private String name; + + // name of the PKCS#11 library + private String library; + + // description to pass to the provider class + private String description; + + // slotID of the slot to use + private int slotID = -1; + + // slot to use, specified as index in the slotlist + private int slotListIndex = -1; + + // set of enabled mechanisms (or null to use default) + private Set enabledMechanisms; + + // set of disabled mechanisms + private Set disabledMechanisms; + + // whether to print debug info during startup + private boolean showInfo = false; + + // template manager, initialized from parsed attributes + private TemplateManager templateManager; + + // how to handle error during startup, one of ERR_ + private int handleStartupErrors = ERR_HALT; + + // flag indicating whether the P11KeyStore should + // be more tolerant of input parameters + private boolean keyStoreCompatibilityMode = true; + + // flag indicating whether we need to explicitly cancel operations + // see Token + private boolean explicitCancel = true; + + // how often to test for token insertion, if no token is present + private int insertionCheckInterval = 2000; + + // flag inidicating whether to omit the call to C_Initialize() + // should be used only if we are running within a process that + // has already called it (e.g. Plugin inside of Mozilla/NSS) + private boolean omitInitialize = false; + + // whether to allow modules that only support single threaded access. + // they cannot be used safely from multiple PKCS#11 consumers in the + // same process, for example NSS and SunPKCS11 + private boolean allowSingleThreadedModules = true; + + // name of the C function that returns the PKCS#11 functionlist + // This option primarily exists for the deprecated + // Secmod.Module.getProvider() method. + private String functionList = "C_GetFunctionList"; + + // whether to use NSS secmod mode. Implicitly set if nssLibraryDirectory, + // nssSecmodDirectory, or nssModule is specified. + private boolean nssUseSecmod; + + // location of the NSS library files (libnss3.so, etc.) + private String nssLibraryDirectory; + + // location of secmod.db + private String nssSecmodDirectory; + + // which NSS module to use + private String nssModule; + + private Secmod.DbMode nssDbMode = Secmod.DbMode.READ_WRITE; + + // Whether the P11KeyStore should specify the CKA_NETSCAPE_DB attribute + // when creating private keys. Only valid if nssUseSecmod is true. + private boolean nssNetscapeDbWorkaround = true; + + // Special init argument string for the NSS softtoken. + // This is used when using the NSS softtoken directly without secmod mode. + private String nssArgs; + + // whether to use NSS trust attributes for the KeyStore of this provider + // this option is for internal use by the SunPKCS11 code only and + // works only for NSS providers created via the Secmod API + private boolean nssUseSecmodTrust = false; + + // Flag to indicate whether the X9.63 encoding for EC points shall be used + // (true) or whether that encoding shall be wrapped in an ASN.1 OctetString + // (false). + private boolean useEcX963Encoding = false; + + // Flag to indicate whether NSS should favour performance (false) or + // memory footprint (true). + private boolean nssOptimizeSpace = false; + + private Config(String filename, InputStream in) throws IOException { + if (in == null) { + if (filename.startsWith("--")) { + // inline config + String config = filename.substring(2).replace("\\n", "\n"); + reader = new StringReader(config); + } else { + in = new FileInputStream(expand(filename)); + } + } + if (reader == null) { + reader = new BufferedReader(new InputStreamReader(in, + StandardCharsets.ISO_8859_1)); + } + parsedKeywords = new HashSet(); + st = new StreamTokenizer(reader); + setupTokenizer(); + parse(); + } + + String getName() { + return name; + } + + String getLibrary() { + return library; + } + + String getDescription() { + if (description != null) { + return description; + } + return "SunPKCS11-" + name + " using library " + library; + } + + int getSlotID() { + return slotID; + } + + int getSlotListIndex() { + if ((slotID == -1) && (slotListIndex == -1)) { + // if neither is set, default to first slot + return 0; + } else { + return slotListIndex; + } + } + + boolean getShowInfo() { + return (SunPKCS11.debug != null) || showInfo; + } + + TemplateManager getTemplateManager() { + if (templateManager == null) { + templateManager = new TemplateManager(); + } + return templateManager; + } + + boolean isEnabled(long m) { + if (enabledMechanisms != null) { + return enabledMechanisms.contains(Long.valueOf(m)); + } + if (disabledMechanisms != null) { + return !disabledMechanisms.contains(Long.valueOf(m)); + } + return true; + } + + int getHandleStartupErrors() { + return handleStartupErrors; + } + + boolean getKeyStoreCompatibilityMode() { + return keyStoreCompatibilityMode; + } + + boolean getExplicitCancel() { + return explicitCancel; + } + + int getInsertionCheckInterval() { + return insertionCheckInterval; + } + + boolean getOmitInitialize() { + return omitInitialize; + } + + boolean getAllowSingleThreadedModules() { + return staticAllowSingleThreadedModules && allowSingleThreadedModules; + } + + String getFunctionList() { + return functionList; + } + + boolean getNssUseSecmod() { + return nssUseSecmod; + } + + String getNssLibraryDirectory() { + return nssLibraryDirectory; + } + + String getNssSecmodDirectory() { + return nssSecmodDirectory; + } + + String getNssModule() { + return nssModule; + } + + Secmod.DbMode getNssDbMode() { + return nssDbMode; + } + + public boolean getNssNetscapeDbWorkaround() { + return nssUseSecmod && nssNetscapeDbWorkaround; + } + + String getNssArgs() { + return nssArgs; + } + + boolean getNssUseSecmodTrust() { + return nssUseSecmodTrust; + } + + boolean getUseEcX963Encoding() { + return useEcX963Encoding; + } + + boolean getNssOptimizeSpace() { + return nssOptimizeSpace; + } + + private static String expand(final String s) throws IOException { + try { + return PropertyExpander.expand(s); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + private void setupTokenizer() { + st.resetSyntax(); + st.wordChars('a', 'z'); + st.wordChars('A', 'Z'); + st.wordChars('0', '9'); + st.wordChars(':', ':'); + st.wordChars('.', '.'); + st.wordChars('_', '_'); + st.wordChars('-', '-'); + st.wordChars('/', '/'); + st.wordChars('\\', '\\'); + st.wordChars('$', '$'); + st.wordChars('{', '{'); // need {} for property subst + st.wordChars('}', '}'); + st.wordChars('*', '*'); + st.wordChars('+', '+'); + st.wordChars('~', '~'); + // XXX check ASCII table and add all other characters except special + + // special: #="(), + st.whitespaceChars(0, ' '); + st.commentChar('#'); + st.eolIsSignificant(true); + st.quoteChar('\"'); + } + + private ConfigurationException excToken(String msg) { + return new ConfigurationException(msg + " " + st); + } + + private ConfigurationException excLine(String msg) { + return new ConfigurationException(msg + ", line " + st.lineno()); + } + + private void parse() throws IOException { + while (true) { + int token = nextToken(); + if (token == TT_EOF) { + break; + } + if (token == TT_EOL) { + continue; + } + if (token != TT_WORD) { + throw excToken("Unexpected token:"); + } + String word = st.sval; + if (word.equals("name")) { + name = parseStringEntry(word); + } else if (word.equals("library")) { + library = parseLibrary(word); + } else if (word.equals("description")) { + parseDescription(word); + } else if (word.equals("slot")) { + parseSlotID(word); + } else if (word.equals("slotListIndex")) { + parseSlotListIndex(word); + } else if (word.equals("enabledMechanisms")) { + parseEnabledMechanisms(word); + } else if (word.equals("disabledMechanisms")) { + parseDisabledMechanisms(word); + } else if (word.equals("attributes")) { + parseAttributes(word); + } else if (word.equals("handleStartupErrors")) { + parseHandleStartupErrors(word); + } else if (word.endsWith("insertionCheckInterval")) { + insertionCheckInterval = parseIntegerEntry(word); + if (insertionCheckInterval < 100) { + throw excLine(word + " must be at least 100 ms"); + } + } else if (word.equals("showInfo")) { + showInfo = parseBooleanEntry(word); + } else if (word.equals("keyStoreCompatibilityMode")) { + keyStoreCompatibilityMode = parseBooleanEntry(word); + } else if (word.equals("explicitCancel")) { + explicitCancel = parseBooleanEntry(word); + } else if (word.equals("omitInitialize")) { + omitInitialize = parseBooleanEntry(word); + } else if (word.equals("allowSingleThreadedModules")) { + allowSingleThreadedModules = parseBooleanEntry(word); + } else if (word.equals("functionList")) { + functionList = parseStringEntry(word); + } else if (word.equals("nssUseSecmod")) { + nssUseSecmod = parseBooleanEntry(word); + } else if (word.equals("nssLibraryDirectory")) { + nssLibraryDirectory = parseLibrary(word); + nssUseSecmod = true; + } else if (word.equals("nssSecmodDirectory")) { + nssSecmodDirectory = expand(parseStringEntry(word)); + nssUseSecmod = true; + } else if (word.equals("nssModule")) { + nssModule = parseStringEntry(word); + nssUseSecmod = true; + } else if (word.equals("nssDbMode")) { + String mode = parseStringEntry(word); + if (mode.equals("readWrite")) { + nssDbMode = Secmod.DbMode.READ_WRITE; + } else if (mode.equals("readOnly")) { + nssDbMode = Secmod.DbMode.READ_ONLY; + } else if (mode.equals("noDb")) { + nssDbMode = Secmod.DbMode.NO_DB; + } else { + throw excToken("nssDbMode must be one of readWrite, readOnly, and noDb:"); + } + nssUseSecmod = true; + } else if (word.equals("nssNetscapeDbWorkaround")) { + nssNetscapeDbWorkaround = parseBooleanEntry(word); + nssUseSecmod = true; + } else if (word.equals("nssArgs")) { + parseNSSArgs(word); + } else if (word.equals("nssUseSecmodTrust")) { + nssUseSecmodTrust = parseBooleanEntry(word); + } else if (word.equals("useEcX963Encoding")) { + useEcX963Encoding = parseBooleanEntry(word); + } else if (word.equals("nssOptimizeSpace")) { + nssOptimizeSpace = parseBooleanEntry(word); + } else { + throw new ConfigurationException + ("Unknown keyword '" + word + "', line " + st.lineno()); + } + parsedKeywords.add(word); + } + reader.close(); + reader = null; + st = null; + parsedKeywords = null; + if (name == null) { + throw new ConfigurationException("name must be specified"); + } + if (nssUseSecmod == false) { + if (library == null) { + throw new ConfigurationException("library must be specified"); + } + } else { + if (library != null) { + throw new ConfigurationException + ("library must not be specified in NSS mode"); + } + if ((slotID != -1) || (slotListIndex != -1)) { + throw new ConfigurationException + ("slot and slotListIndex must not be specified in NSS mode"); + } + if (nssArgs != null) { + throw new ConfigurationException + ("nssArgs must not be specified in NSS mode"); + } + if (nssUseSecmodTrust != false) { + throw new ConfigurationException("nssUseSecmodTrust is an " + + "internal option and must not be specified in NSS mode"); + } + } + } + + // + // Parsing helper methods + // + + private int nextToken() throws IOException { + int token = st.nextToken(); + debug(st); + return token; + } + + private void parseEquals() throws IOException { + int token = nextToken(); + if (token != '=') { + throw excToken("Expected '=', read"); + } + } + + private void parseOpenBraces() throws IOException { + while (true) { + int token = nextToken(); + if (token == TT_EOL) { + continue; + } + if ((token == TT_WORD) && st.sval.equals("{")) { + return; + } + throw excToken("Expected '{', read"); + } + } + + private boolean isCloseBraces(int token) { + return (token == TT_WORD) && st.sval.equals("}"); + } + + private String parseWord() throws IOException { + int token = nextToken(); + if (token != TT_WORD) { + throw excToken("Unexpected value:"); + } + return st.sval; + } + + private String parseStringEntry(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + + int token = nextToken(); + if (token != TT_WORD && token != '\"') { + // not a word token nor a string enclosed by double quotes + throw excToken("Unexpected value:"); + } + String value = st.sval; + + debug(keyword + ": " + value); + return value; + } + + private boolean parseBooleanEntry(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + boolean value = parseBoolean(); + debug(keyword + ": " + value); + return value; + } + + private int parseIntegerEntry(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + int value = decodeNumber(parseWord()); + debug(keyword + ": " + value); + return value; + } + + private boolean parseBoolean() throws IOException { + String val = parseWord(); + switch (val) { + case "true": + return true; + case "false": + return false; + default: + throw excToken("Expected boolean value, read:"); + } + } + + private String parseLine() throws IOException { + // allow quoted string as part of line + String s = null; + while (true) { + int token = nextToken(); + if ((token == TT_EOL) || (token == TT_EOF)) { + break; + } + if (token != TT_WORD && token != '\"') { + throw excToken("Unexpected value"); + } + if (s == null) { + s = st.sval; + } else { + s = s + " " + st.sval; + } + } + if (s == null) { + throw excToken("Unexpected empty line"); + } + return s; + } + + private int decodeNumber(String str) throws IOException { + try { + if (str.startsWith("0x") || str.startsWith("0X")) { + return Integer.parseInt(str.substring(2), 16); + } else { + return Integer.parseInt(str); + } + } catch (NumberFormatException e) { + throw excToken("Expected number, read"); + } + } + + private static boolean isNumber(String s) { + if (s.length() == 0) { + return false; + } + char ch = s.charAt(0); + return ((ch >= '0') && (ch <= '9')); + } + + private void parseComma() throws IOException { + int token = nextToken(); + if (token != ',') { + throw excToken("Expected ',', read"); + } + } + + private static boolean isByteArray(String val) { + return val.startsWith("0h"); + } + + private byte[] decodeByteArray(String str) throws IOException { + if (str.startsWith("0h") == false) { + throw excToken("Expected byte array value, read"); + } + str = str.substring(2); + // XXX proper hex parsing + try { + return new BigInteger(str, 16).toByteArray(); + } catch (NumberFormatException e) { + throw excToken("Expected byte array value, read"); + } + } + + private void checkDup(String keyword) throws IOException { + if (parsedKeywords.contains(keyword)) { + throw excLine(keyword + " must only be specified once"); + } + } + + // + // individual entry parsing methods + // + + private String parseLibrary(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + String lib = parseLine(); + lib = expand(lib); + int i = lib.indexOf("/$ISA/"); + if (i != -1) { + // replace "/$ISA/" with "/sparcv9/" on 64-bit Solaris SPARC + // and with "/amd64/" on Solaris AMD64. + // On all other platforms, just turn it into a "/" + String osName = System.getProperty("os.name", ""); + String osArch = System.getProperty("os.arch", ""); + String prefix = lib.substring(0, i); + String suffix = lib.substring(i + 5); + if (osName.equals("SunOS") && osArch.equals("sparcv9")) { + lib = prefix + "/sparcv9" + suffix; + } else if (osName.equals("SunOS") && osArch.equals("amd64")) { + lib = prefix + "/amd64" + suffix; + } else { + lib = prefix + suffix; + } + } + debug(keyword + ": " + lib); + + // Check to see if full path is specified to prevent the DLL + // preloading attack + if (!(new File(lib)).isAbsolute()) { + throw new ConfigurationException( + "Absolute path required for library value: " + lib); + } + return lib; + } + + private void parseDescription(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + description = parseLine(); + debug("description: " + description); + } + + private void parseSlotID(String keyword) throws IOException { + if (slotID >= 0) { + throw excLine("Duplicate slot definition"); + } + if (slotListIndex >= 0) { + throw excLine + ("Only one of slot and slotListIndex must be specified"); + } + parseEquals(); + String slotString = parseWord(); + slotID = decodeNumber(slotString); + debug("slot: " + slotID); + } + + private void parseSlotListIndex(String keyword) throws IOException { + if (slotListIndex >= 0) { + throw excLine("Duplicate slotListIndex definition"); + } + if (slotID >= 0) { + throw excLine + ("Only one of slot and slotListIndex must be specified"); + } + parseEquals(); + String slotString = parseWord(); + slotListIndex = decodeNumber(slotString); + debug("slotListIndex: " + slotListIndex); + } + + private void parseEnabledMechanisms(String keyword) throws IOException { + enabledMechanisms = parseMechanisms(keyword); + } + + private void parseDisabledMechanisms(String keyword) throws IOException { + disabledMechanisms = parseMechanisms(keyword); + } + + private Set parseMechanisms(String keyword) throws IOException { + checkDup(keyword); + Set mechs = new HashSet(); + parseEquals(); + parseOpenBraces(); + while (true) { + int token = nextToken(); + if (isCloseBraces(token)) { + break; + } + if (token == TT_EOL) { + continue; + } + if (token != TT_WORD) { + throw excToken("Expected mechanism, read"); + } + long mech = parseMechanism(st.sval); + mechs.add(Long.valueOf(mech)); + } + if (DEBUG) { + System.out.print("mechanisms: ["); + for (Long mech : mechs) { + System.out.print(Functions.getMechanismName(mech)); + System.out.print(", "); + } + System.out.println("]"); + } + return mechs; + } + + private long parseMechanism(String mech) throws IOException { + if (isNumber(mech)) { + return decodeNumber(mech); + } else { + try { + return Functions.getMechanismId(mech); + } catch (IllegalArgumentException e) { + throw excLine("Unknown mechanism: " + mech); + } + } + } + + private void parseAttributes(String keyword) throws IOException { + if (templateManager == null) { + templateManager = new TemplateManager(); + } + int token = nextToken(); + if (token == '=') { + String s = parseWord(); + if (s.equals("compatibility") == false) { + throw excLine("Expected 'compatibility', read " + s); + } + setCompatibilityAttributes(); + return; + } + if (token != '(') { + throw excToken("Expected '(' or '=', read"); + } + String op = parseOperation(); + parseComma(); + long objectClass = parseObjectClass(); + parseComma(); + long keyAlg = parseKeyAlgorithm(); + token = nextToken(); + if (token != ')') { + throw excToken("Expected ')', read"); + } + parseEquals(); + parseOpenBraces(); + List attributes = new ArrayList(); + while (true) { + token = nextToken(); + if (isCloseBraces(token)) { + break; + } + if (token == TT_EOL) { + continue; + } + if (token != TT_WORD) { + throw excToken("Expected mechanism, read"); + } + String attributeName = st.sval; + long attributeId = decodeAttributeName(attributeName); + parseEquals(); + String attributeValue = parseWord(); + attributes.add(decodeAttributeValue(attributeId, attributeValue)); + } + templateManager.addTemplate + (op, objectClass, keyAlg, attributes.toArray(CK_A0)); + } + + private void setCompatibilityAttributes() { + // all secret keys + templateManager.addTemplate(O_ANY, CKO_SECRET_KEY, PCKK_ANY, + new CK_ATTRIBUTE[] { + TOKEN_FALSE, + SENSITIVE_FALSE, + EXTRACTABLE_TRUE, + ENCRYPT_TRUE, + DECRYPT_TRUE, + WRAP_TRUE, + UNWRAP_TRUE, + }); + + // generic secret keys are special + // They are used as MAC keys plus for the SSL/TLS (pre)master secrets + templateManager.addTemplate(O_ANY, CKO_SECRET_KEY, CKK_GENERIC_SECRET, + new CK_ATTRIBUTE[] { + SIGN_TRUE, + VERIFY_TRUE, + ENCRYPT_NULL, + DECRYPT_NULL, + WRAP_NULL, + UNWRAP_NULL, + DERIVE_TRUE, + }); + + // all private and public keys + templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, PCKK_ANY, + new CK_ATTRIBUTE[] { + TOKEN_FALSE, + SENSITIVE_FALSE, + EXTRACTABLE_TRUE, + }); + templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, PCKK_ANY, + new CK_ATTRIBUTE[] { + TOKEN_FALSE, + }); + + // additional attributes for RSA private keys + templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_RSA, + new CK_ATTRIBUTE[] { + DECRYPT_TRUE, + SIGN_TRUE, + SIGN_RECOVER_TRUE, + UNWRAP_TRUE, + }); + // additional attributes for RSA public keys + templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, CKK_RSA, + new CK_ATTRIBUTE[] { + ENCRYPT_TRUE, + VERIFY_TRUE, + VERIFY_RECOVER_TRUE, + WRAP_TRUE, + }); + + // additional attributes for DSA private keys + templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_DSA, + new CK_ATTRIBUTE[] { + SIGN_TRUE, + }); + // additional attributes for DSA public keys + templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, CKK_DSA, + new CK_ATTRIBUTE[] { + VERIFY_TRUE, + }); + + // additional attributes for DH private keys + templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_DH, + new CK_ATTRIBUTE[] { + DERIVE_TRUE, + }); + + // additional attributes for EC private keys + templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_EC, + new CK_ATTRIBUTE[] { + SIGN_TRUE, + DERIVE_TRUE, + }); + // additional attributes for EC public keys + templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, CKK_EC, + new CK_ATTRIBUTE[] { + VERIFY_TRUE, + }); + } + + private final static CK_ATTRIBUTE[] CK_A0 = new CK_ATTRIBUTE[0]; + + private String parseOperation() throws IOException { + String op = parseWord(); + switch (op) { + case "*": + return TemplateManager.O_ANY; + case "generate": + return TemplateManager.O_GENERATE; + case "import": + return TemplateManager.O_IMPORT; + default: + throw excLine("Unknown operation " + op); + } + } + + private long parseObjectClass() throws IOException { + String name = parseWord(); + try { + return Functions.getObjectClassId(name); + } catch (IllegalArgumentException e) { + throw excLine("Unknown object class " + name); + } + } + + private long parseKeyAlgorithm() throws IOException { + String name = parseWord(); + if (isNumber(name)) { + return decodeNumber(name); + } else { + try { + return Functions.getKeyId(name); + } catch (IllegalArgumentException e) { + throw excLine("Unknown key algorithm " + name); + } + } + } + + private long decodeAttributeName(String name) throws IOException { + if (isNumber(name)) { + return decodeNumber(name); + } else { + try { + return Functions.getAttributeId(name); + } catch (IllegalArgumentException e) { + throw excLine("Unknown attribute name " + name); + } + } + } + + private CK_ATTRIBUTE decodeAttributeValue(long id, String value) + throws IOException { + if (value.equals("null")) { + return new CK_ATTRIBUTE(id); + } else if (value.equals("true")) { + return new CK_ATTRIBUTE(id, true); + } else if (value.equals("false")) { + return new CK_ATTRIBUTE(id, false); + } else if (isByteArray(value)) { + return new CK_ATTRIBUTE(id, decodeByteArray(value)); + } else if (isNumber(value)) { + return new CK_ATTRIBUTE(id, Integer.valueOf(decodeNumber(value))); + } else { + throw excLine("Unknown attribute value " + value); + } + } + + private void parseNSSArgs(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + int token = nextToken(); + if (token != '"') { + throw excToken("Expected quoted string"); + } + nssArgs = expand(st.sval); + debug("nssArgs: " + nssArgs); + } + + private void parseHandleStartupErrors(String keyword) throws IOException { + checkDup(keyword); + parseEquals(); + String val = parseWord(); + if (val.equals("ignoreAll")) { + handleStartupErrors = ERR_IGNORE_ALL; + } else if (val.equals("ignoreMissingLibrary")) { + handleStartupErrors = ERR_IGNORE_LIB; + } else if (val.equals("halt")) { + handleStartupErrors = ERR_HALT; + } else { + throw excToken("Invalid value for handleStartupErrors:"); + } + debug("handleStartupErrors: " + handleStartupErrors); + } + +} + +class ConfigurationException extends IOException { + private static final long serialVersionUID = 254492758807673194L; + ConfigurationException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/KeyCache.java b/src/main/java/com/sunyard/security/pkcs11/KeyCache.java new file mode 100644 index 0000000..bb9b219 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/KeyCache.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; +import java.lang.ref.*; + +import java.security.Key; + +import sun.security.util.Cache; + +/** + * Key to P11Key translation cache. The PKCS#11 token can only perform + * operations on keys stored on the token (permanently or temporarily). That + * means that in order to allow the PKCS#11 provider to use keys from other + * providers, we need to transparently convert them to P11Keys. The engines + * do that using (Secret)KeyFactories, which in turn use this class as a + * cache. + * + * There are two KeyCache instances per provider, one for secret keys and + * one for public and private keys. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class KeyCache { + + private final Cache strongCache; + + private WeakReference> cacheReference; + + KeyCache() { + strongCache = Cache.newHardMemoryCache(16); + } + + private static final class IdentityWrapper { + final Object obj; + IdentityWrapper(Object obj) { + this.obj = obj; + } + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof IdentityWrapper == false) { + return false; + } + IdentityWrapper other = (IdentityWrapper)o; + return this.obj == other.obj; + } + public int hashCode() { + return System.identityHashCode(obj); + } + } + + synchronized P11Key get(Key key) { + P11Key p11Key = strongCache.get(new IdentityWrapper(key)); + if (p11Key != null) { + return p11Key; + } + Map map = + (cacheReference == null) ? null : cacheReference.get(); + if (map == null) { + return null; + } + return map.get(key); + } + + synchronized void put(Key key, P11Key p11Key) { + strongCache.put(new IdentityWrapper(key), p11Key); + Map map = + (cacheReference == null) ? null : cacheReference.get(); + if (map == null) { + map = new IdentityHashMap<>(); + cacheReference = new WeakReference<>(map); + } + map.put(key, p11Key); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/MessageDigestSpi2.java b/src/main/java/com/sunyard/security/pkcs11/MessageDigestSpi2.java new file mode 100644 index 0000000..3956442 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/MessageDigestSpi2.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.InvalidKeyException; +import javax.crypto.SecretKey; + +/** + * Special interface for additional MessageDigestSpi method(s). + */ +public interface MessageDigestSpi2 { + + /** + * Updates the digest using the specified key. + * This is used for SSL 3.0 only, we may deprecate and remove the support + * of this in the future + * + * @param key the key whose value is to be digested. + */ + void engineUpdate(SecretKey key) throws InvalidKeyException; +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11AEADCipher.java b/src/main/java/com/sunyard/security/pkcs11/P11AEADCipher.java new file mode 100644 index 0000000..fa156f0 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11AEADCipher.java @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sunyard.security.pkcs11; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Locale; + +import java.security.*; +import java.security.spec.*; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.nio.ch.DirectBuffer; +import sun.security.jca.JCAUtil; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * P11 AEAD Cipher implementation class. This class currently supports + * AES with GCM mode. + * + * Note that AEAD modes do not use padding, so this class does not have + * its own padding impl. In addition, NSS CKM_AES_GCM only supports single-part + * encryption/decryption, thus the current impl uses PKCS#11 C_Encrypt/C_Decrypt + * calls and buffers data until doFinal is called. + * + * Note that PKCS#11 standard currently only supports GCM and CCM AEAD modes. + * There are no provisions for other AEAD modes yet. + * + * @since 13 + */ +final class P11AEADCipher extends CipherSpi { + + // mode constant for GCM mode + private static final int MODE_GCM = 10; + + // default constants for GCM + private static final int GCM_DEFAULT_TAG_LEN = 16; + private static final int GCM_DEFAULT_IV_LEN = 16; + + private static final String ALGO = "AES"; + + // token instance + private final Token token; + + // mechanism id + private final long mechanism; + + // mode, one of MODE_* above + private final int blockMode; + + // acceptable key size, -1 if more than 1 key sizes are accepted + private final int fixedKeySize; + + // associated session, if any + private Session session = null; + + // key, if init() was called + private P11Key p11Key = null; + + // flag indicating whether an operation is initialized + private boolean initialized = false; + + // falg indicating encrypt or decrypt mode + private boolean encrypt = true; + + // parameters + private byte[] iv = null; + private int tagLen = -1; + private SecureRandom random = JCAUtil.getSecureRandom(); + + // dataBuffer is cleared upon doFinal calls + private ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream(); + // aadBuffer is cleared upon successful init calls + private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream(); + private boolean updateCalled = false; + + private boolean requireReinit = false; + private P11Key lastEncKey = null; + private byte[] lastEncIv = null; + + P11AEADCipher(Token token, String algorithm, long mechanism) + throws PKCS11Exception, NoSuchAlgorithmException { + super(); + this.token = token; + this.mechanism = mechanism; + + String[] algoParts = algorithm.split("/"); + if (algoParts.length != 3) { + throw new ProviderException("Unsupported Transformation format: " + + algorithm); + } + if (!algoParts[0].startsWith("AES")) { + throw new ProviderException("Only support AES for AEAD cipher mode"); + } + int index = algoParts[0].indexOf('_'); + if (index != -1) { + // should be well-formed since we specify what we support + fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1)) >> 3; + } else { + fixedKeySize = -1; + } + this.blockMode = parseMode(algoParts[1]); + if (!algoParts[2].equals("NoPadding")) { + throw new ProviderException("Only NoPadding is supported for AEAD cipher mode"); + } + } + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + // Disallow change of mode for now since currently it's explicitly + // defined in transformation strings + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + + private int parseMode(String mode) throws NoSuchAlgorithmException { + mode = mode.toUpperCase(Locale.ENGLISH); + int result; + if (mode.equals("GCM")) { + result = MODE_GCM; + } else { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + return result; + } + + // see JCE spec + protected void engineSetPadding(String padding) + throws NoSuchPaddingException { + // Disallow change of padding for now since currently it's explicitly + // defined in transformation strings + throw new NoSuchPaddingException("Unsupported padding " + padding); + } + + // see JCE spec + protected int engineGetBlockSize() { + return 16; // constant; only AES is supported + } + + // see JCE spec + protected int engineGetOutputSize(int inputLen) { + return doFinalLength(inputLen); + } + + // see JCE spec + protected byte[] engineGetIV() { + return (iv == null) ? null : iv.clone(); + } + + // see JCE spec + protected AlgorithmParameters engineGetParameters() { + if (encrypt && iv == null && tagLen == -1) { + switch (blockMode) { + case MODE_GCM: + iv = new byte[GCM_DEFAULT_IV_LEN]; + tagLen = GCM_DEFAULT_TAG_LEN; + break; + default: + throw new ProviderException("Unsupported mode"); + } + random.nextBytes(iv); + } + try { + AlgorithmParameterSpec spec; + String apAlgo; + switch (blockMode) { + case MODE_GCM: + apAlgo = "GCM"; + spec = new GCMParameterSpec(tagLen << 3, iv); + break; + default: + throw new ProviderException("Unsupported mode"); + } + AlgorithmParameters params = + AlgorithmParameters.getInstance(apAlgo); + params.init(spec); + return params; + } catch (GeneralSecurityException e) { + // NoSuchAlgorithmException, NoSuchProviderException + // InvalidParameterSpecException + throw new ProviderException("Could not encode parameters", e); + } + } + + // see JCE spec + protected void engineInit(int opmode, Key key, SecureRandom sr) + throws InvalidKeyException { + if (opmode == Cipher.DECRYPT_MODE) { + throw new InvalidKeyException("Parameters required for decryption"); + } + updateCalled = false; + try { + implInit(opmode, key, null, -1, sr); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidKeyException("init() failed", e); + } + } + + // see JCE spec + protected void engineInit(int opmode, Key key, + AlgorithmParameterSpec params, SecureRandom sr) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (opmode == Cipher.DECRYPT_MODE && params == null) { + throw new InvalidAlgorithmParameterException + ("Parameters required for decryption"); + } + updateCalled = false; + byte[] ivValue = null; + int tagLen = -1; + if (params != null) { + switch (blockMode) { + case MODE_GCM: + if (!(params instanceof GCMParameterSpec)) { + throw new InvalidAlgorithmParameterException + ("Only GCMParameterSpec is supported"); + } + ivValue = ((GCMParameterSpec) params).getIV(); + tagLen = ((GCMParameterSpec) params).getTLen() >> 3; + break; + default: + throw new ProviderException("Unsupported mode"); + } + } + implInit(opmode, key, ivValue, tagLen, sr); + } + + // see JCE spec + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom sr) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (opmode == Cipher.DECRYPT_MODE && params == null) { + throw new InvalidAlgorithmParameterException + ("Parameters required for decryption"); + } + updateCalled = false; + try { + AlgorithmParameterSpec paramSpec = null; + if (params != null) { + switch (blockMode) { + case MODE_GCM: + paramSpec = + params.getParameterSpec(GCMParameterSpec.class); + break; + default: + throw new ProviderException("Unsupported mode"); + } + } + engineInit(opmode, key, paramSpec, sr); + } catch (InvalidParameterSpecException ex) { + throw new InvalidAlgorithmParameterException(ex); + } + } + + // actual init() implementation + private void implInit(int opmode, Key key, byte[] iv, int tagLen, + SecureRandom sr) + throws InvalidKeyException, InvalidAlgorithmParameterException { + reset(true); + if (fixedKeySize != -1 && + ((key instanceof P11Key) ? ((P11Key) key).length() >> 3 : + key.getEncoded().length) != fixedKeySize) { + throw new InvalidKeyException("Key size is invalid"); + } + P11Key newKey = P11SecretKeyFactory.convertKey(token, key, ALGO); + switch (opmode) { + case Cipher.ENCRYPT_MODE: + encrypt = true; + requireReinit = Arrays.equals(iv, lastEncIv) && + (newKey == lastEncKey); + if (requireReinit) { + throw new InvalidAlgorithmParameterException + ("Cannot reuse iv for GCM encryption"); + } + break; + case Cipher.DECRYPT_MODE: + encrypt = false; + requireReinit = false; + break; + default: + throw new InvalidAlgorithmParameterException + ("Unsupported mode: " + opmode); + } + + // decryption without parameters is checked in all engineInit() calls + if (sr != null) { + this.random = sr; + } + if (iv == null && tagLen == -1) { + // generate default values + switch (blockMode) { + case MODE_GCM: + iv = new byte[GCM_DEFAULT_IV_LEN]; + this.random.nextBytes(iv); + tagLen = GCM_DEFAULT_TAG_LEN; + break; + default: + throw new ProviderException("Unsupported mode"); + } + } + this.iv = iv; + this.tagLen = tagLen; + this.p11Key = newKey; + try { + initialize(); + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not initialize cipher", e); + } + } + + private void cancelOperation() { + // cancel operation by finishing it; avoid killSession as some + // hardware vendors may require re-login + int bufLen = doFinalLength(0); + byte[] buffer = new byte[bufLen]; + byte[] in = dataBuffer.toByteArray(); + int inLen = in.length; + try { + if (encrypt) { + token.p11.C_Encrypt(session.id(), 0, in, 0, inLen, + 0, buffer, 0, bufLen); + } else { + token.p11.C_Decrypt(session.id(), 0, in, 0, inLen, + 0, buffer, 0, bufLen); + } + } catch (PKCS11Exception e) { + if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { + // Cancel Operation may be invoked after an error on a PKCS#11 + // call. If the operation inside the token was already cancelled, + // do not fail here. This is part of a defensive mechanism for + // PKCS#11 libraries that do not strictly follow the standard. + return; + } + if (encrypt) { + throw new ProviderException("Cancel failed", e); + } + // ignore failure for decryption + } + } + + private void ensureInitialized() throws PKCS11Exception { + if (initialized && aadBuffer.size() > 0) { + // need to cancel first to avoid CKR_OPERATION_ACTIVE + reset(true); + } + if (!initialized) { + initialize(); + } + } + + private void initialize() throws PKCS11Exception { + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without" + + " calling engineInit first"); + } + if (requireReinit) { + throw new IllegalStateException + ("Must use either different key or iv for GCM encryption"); + } + + token.ensureValid(); + + byte[] aad = (aadBuffer.size() > 0? aadBuffer.toByteArray() : null); + + long p11KeyID = p11Key.getKeyID(); + try { + CK_MECHANISM mechWithParams; + switch (blockMode) { + case MODE_GCM: + mechWithParams = new CK_MECHANISM(mechanism, + new CK_GCM_PARAMS(tagLen << 3, iv, aad)); + break; + default: + throw new ProviderException("Unsupported mode: " + blockMode); + } + if (session == null) { + session = token.getOpSession(); + } + if (encrypt) { + token.p11.C_EncryptInit(session.id(), mechWithParams, + p11KeyID); + } else { + token.p11.C_DecryptInit(session.id(), mechWithParams, + p11KeyID); + } + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw e; + } finally { + dataBuffer.reset(); + aadBuffer.reset(); + } + initialized = true; + } + + // if doFinal(inLen) is called, how big does the output buffer have to be? + private int doFinalLength(int inLen) { + if (inLen < 0) { + throw new ProviderException("Invalid negative input length"); + } + + int result = inLen + dataBuffer.size(); + if (encrypt) { + result += tagLen; + } else { + // PKCS11Exception: CKR_BUFFER_TOO_SMALL + //result -= tagLen; + } + return result; + } + + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + + try { + if (session == null) { + return; + } + + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + dataBuffer.reset(); + } + } + + // see JCE spec + protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { + updateCalled = true; + int n = implUpdate(in, inOfs, inLen); + return new byte[0]; + } + + // see JCE spec + protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws ShortBufferException { + updateCalled = true; + implUpdate(in, inOfs, inLen); + return 0; + } + + // see JCE spec + @Override + protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) + throws ShortBufferException { + updateCalled = true; + implUpdate(inBuffer); + return 0; + } + + // see JCE spec + @Override + protected synchronized void engineUpdateAAD(byte[] src, int srcOfs, int srcLen) + throws IllegalStateException { + if ((src == null) || (srcOfs < 0) || (srcOfs + srcLen > src.length)) { + throw new IllegalArgumentException("Invalid AAD"); + } + if (requireReinit) { + throw new IllegalStateException + ("Must use either different key or iv for GCM encryption"); + } + if (p11Key == null) { + throw new IllegalStateException("Need to initialize Cipher first"); + } + if (updateCalled) { + throw new IllegalStateException + ("Update has been called; no more AAD data"); + } + aadBuffer.write(src, srcOfs, srcLen); + } + + // see JCE spec + @Override + protected void engineUpdateAAD(ByteBuffer src) + throws IllegalStateException { + if (src == null) { + throw new IllegalArgumentException("Invalid AAD"); + } + byte[] srcBytes = new byte[src.remaining()]; + src.get(srcBytes); + engineUpdateAAD(srcBytes, 0, srcBytes.length); + } + + // see JCE spec + protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) + throws IllegalBlockSizeException, BadPaddingException { + int minOutLen = doFinalLength(inLen); + try { + byte[] out = new byte[minOutLen]; + int n = engineDoFinal(in, inOfs, inLen, out, 0); + return P11Util.convert(out, 0, n); + } catch (ShortBufferException e) { + // convert since the output length is calculated by doFinalLength() + throw new ProviderException(e); + } finally { + updateCalled = false; + } + } + // see JCE spec + protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + try { + return implDoFinal(in, inOfs, inLen, out, outOfs, out.length - outOfs); + } finally { + updateCalled = false; + } + } + + // see JCE spec + @Override + protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + try { + return implDoFinal(inBuffer, outBuffer); + } finally { + updateCalled = false; + } + } + + private int implUpdate(byte[] in, int inOfs, int inLen) { + if (inLen > 0) { + updateCalled = true; + try { + ensureInitialized(); + } catch (PKCS11Exception e) { + //e.printStackTrace(); + reset(false); + throw new ProviderException("update() failed", e); + } + dataBuffer.write(in, inOfs, inLen); + } + // always 0 as NSS only supports single-part encryption/decryption + return 0; + } + + private int implUpdate(ByteBuffer inBuf) { + int inLen = inBuf.remaining(); + if (inLen > 0) { + try { + ensureInitialized(); + } catch (PKCS11Exception e) { + reset(false); + throw new ProviderException("update() failed", e); + } + byte[] data = new byte[inLen]; + inBuf.get(data); + dataBuffer.write(data, 0, data.length); + } + // always 0 as NSS only supports single-part encryption/decryption + return 0; + } + + private int implDoFinal(byte[] in, int inOfs, int inLen, + byte[] out, int outOfs, int outLen) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + int requiredOutLen = doFinalLength(inLen); + if (outLen < requiredOutLen) { + throw new ShortBufferException(); + } + boolean doCancel = true; + try { + ensureInitialized(); + if (dataBuffer.size() > 0) { + if (in != null && inOfs > 0 && inLen > 0 && + inOfs < (in.length - inLen)) { + dataBuffer.write(in, inOfs, inLen); + } + in = dataBuffer.toByteArray(); + inOfs = 0; + inLen = in.length; + } + int k = 0; + if (encrypt) { + k = token.p11.C_Encrypt(session.id(), 0, in, inOfs, inLen, + 0, out, outOfs, outLen); + doCancel = false; + } else { + // Special handling to match SunJCE provider behavior + if (inLen == 0) { + return 0; + } + k = token.p11.C_Decrypt(session.id(), 0, in, inOfs, inLen, + 0, out, outOfs, outLen); + doCancel = false; + } + return k; + } catch (PKCS11Exception e) { + // As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only + // keep the operation active on CKR_BUFFER_TOO_SMALL errors or + // successful calls to determine the output length. However, + // these cases are not expected here because the output length + // is checked in the OpenJDK side before making the PKCS#11 call. + // Thus, doCancel can safely be 'false'. + doCancel = false; + handleException(e); + throw new ProviderException("doFinal() failed", e); + } finally { + if (encrypt) { + lastEncKey = this.p11Key; + lastEncIv = this.iv; + requireReinit = true; + } + reset(doCancel); + } + } + + private int implDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + int outLen = outBuffer.remaining(); + int inLen = inBuffer.remaining(); + + int requiredOutLen = doFinalLength(inLen); + if (outLen < requiredOutLen) { + throw new ShortBufferException(); + } + + boolean doCancel = true; + try { + ensureInitialized(); + + long inAddr = 0; + byte[] in = null; + int inOfs = 0; + if (dataBuffer.size() > 0) { + if (inLen > 0) { + byte[] temp = new byte[inLen]; + inBuffer.get(temp); + dataBuffer.write(temp, 0, temp.length); + } + in = dataBuffer.toByteArray(); + inOfs = 0; + inLen = in.length; + } else { + if (inBuffer instanceof DirectBuffer) { + inAddr = ((DirectBuffer) inBuffer).address(); + inOfs = inBuffer.position(); + } else { + if (inBuffer.hasArray()) { + in = inBuffer.array(); + inOfs = inBuffer.position() + inBuffer.arrayOffset(); + } else { + in = new byte[inLen]; + inBuffer.get(in); + } + } + } + long outAddr = 0; + byte[] outArray = null; + int outOfs = 0; + if (outBuffer instanceof DirectBuffer) { + outAddr = ((DirectBuffer) outBuffer).address(); + outOfs = outBuffer.position(); + } else { + if (outBuffer.hasArray()) { + outArray = outBuffer.array(); + outOfs = outBuffer.position() + outBuffer.arrayOffset(); + } else { + outArray = new byte[outLen]; + } + } + + int k = 0; + if (encrypt) { + k = token.p11.C_Encrypt(session.id(), inAddr, in, inOfs, inLen, + outAddr, outArray, outOfs, outLen); + doCancel = false; + } else { + // Special handling to match SunJCE provider behavior + if (inLen == 0) { + return 0; + } + k = token.p11.C_Decrypt(session.id(), inAddr, in, inOfs, inLen, + outAddr, outArray, outOfs, outLen); + doCancel = false; + } + outBuffer.position(outBuffer.position() + k); + return k; + } catch (PKCS11Exception e) { + // As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only + // keep the operation active on CKR_BUFFER_TOO_SMALL errors or + // successful calls to determine the output length. However, + // these cases are not expected here because the output length + // is checked in the OpenJDK side before making the PKCS#11 call. + // Thus, doCancel can safely be 'false'. + doCancel = false; + handleException(e); + throw new ProviderException("doFinal() failed", e); + } finally { + if (encrypt) { + lastEncKey = this.p11Key; + lastEncIv = this.iv; + requireReinit = true; + } + reset(doCancel); + } + } + + private void handleException(PKCS11Exception e) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + long errorCode = e.getErrorCode(); + if (errorCode == CKR_BUFFER_TOO_SMALL) { + throw (ShortBufferException) + (new ShortBufferException().initCause(e)); + } else if (errorCode == CKR_DATA_LEN_RANGE || + errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) { + throw (IllegalBlockSizeException) + (new IllegalBlockSizeException(e.toString()).initCause(e)); + } else if (errorCode == CKR_ENCRYPTED_DATA_INVALID || + // Solaris-specific + errorCode == CKR_GENERAL_ERROR) { + throw (BadPaddingException) + (new BadPaddingException(e.toString()).initCause(e)); + } + } + + // see JCE spec + protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, + InvalidKeyException { + // XXX key wrapping + throw new UnsupportedOperationException("engineWrap()"); + } + + // see JCE spec + protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException { + // XXX key unwrapping + throw new UnsupportedOperationException("engineUnwrap()"); + } + + // see JCE spec + @Override + protected int engineGetKeySize(Key key) throws InvalidKeyException { + int n = P11SecretKeyFactory.convertKey + (token, key, ALGO).length(); + return n; + } +} + diff --git a/src/main/java/com/sunyard/security/pkcs11/P11Cipher.java b/src/main/java/com/sunyard/security/pkcs11/P11Cipher.java new file mode 100644 index 0000000..882dde6 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11Cipher.java @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sunyard.security.pkcs11; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Locale; + +import java.security.*; +import java.security.spec.*; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.nio.ch.DirectBuffer; +import sun.security.jca.JCAUtil; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * Cipher implementation class. This class currently supports + * DES, DESede, AES, ARCFOUR, and Blowfish. + * + * This class is designed to support ECB, CBC, CTR with NoPadding + * and ECB, CBC with PKCS5Padding. It will use its own padding impl + * if the native mechanism does not support padding. + * + * Note that PKCS#11 currently only supports ECB, CBC, and CTR. + * There are no provisions for other modes such as CFB, OFB, and PCBC. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11Cipher extends CipherSpi { + + // mode constant for ECB mode + private final static int MODE_ECB = 3; + // mode constant for CBC mode + private final static int MODE_CBC = 4; + // mode constant for CTR mode + private final static int MODE_CTR = 5; + + // padding constant for NoPadding + private final static int PAD_NONE = 5; + // padding constant for PKCS5Padding + private final static int PAD_PKCS5 = 6; + + private static interface Padding { + // ENC: format the specified buffer with padding bytes and return the + // actual padding length + int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen); + + // DEC: return the length of trailing padding bytes given the specified + // padded data + int unpad(byte[] paddedData, int len) + throws BadPaddingException, IllegalBlockSizeException; + } + + private static class PKCS5Padding implements Padding { + + private final int blockSize; + + PKCS5Padding(int blockSize) + throws NoSuchPaddingException { + if (blockSize == 0) { + throw new NoSuchPaddingException + ("PKCS#5 padding not supported with stream ciphers"); + } + this.blockSize = blockSize; + } + + public int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen) { + Arrays.fill(paddingBuffer, startOff, startOff + padLen, (byte) (padLen & 0x007f)); + return padLen; + } + + public int unpad(byte[] paddedData, int len) + throws BadPaddingException, IllegalBlockSizeException { + if ((len < 1) || (len % blockSize != 0)) { + throw new IllegalBlockSizeException + ("Input length must be multiples of " + blockSize); + } + byte padValue = paddedData[len - 1]; + if (padValue < 1 || padValue > blockSize) { + throw new BadPaddingException("Invalid pad value!"); + } + // sanity check padding bytes + int padStartIndex = len - padValue; + for (int i = padStartIndex; i < len; i++) { + if (paddedData[i] != padValue) { + throw new BadPaddingException("Invalid pad bytes!"); + } + } + return padValue; + } + } + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // name of the key algorithm, e.g. DES instead of algorithm DES/CBC/... + private final String keyAlgorithm; + + // mechanism id + private final long mechanism; + + // associated session, if any + private Session session; + + // key, if init() was called + private P11Key p11Key; + + // flag indicating whether an operation is initialized + private boolean initialized; + + // falg indicating encrypt or decrypt mode + private boolean encrypt; + + // mode, one of MODE_* above (MODE_ECB for stream ciphers) + private int blockMode; + + // block size, 0 for stream ciphers + private final int blockSize; + + // padding type, on of PAD_* above (PAD_NONE for stream ciphers) + private int paddingType; + + // when the padding is requested but unsupported by the native mechanism, + // we use the following to do padding and necessary data buffering. + // padding object which generate padding and unpad the decrypted data + private Padding paddingObj; + // buffer for holding back the block which contains padding bytes + private byte[] padBuffer; + private int padBufferLen; + + // original IV, if in MODE_CBC or MODE_CTR + private byte[] iv; + + // number of bytes buffered internally by the native mechanism and padBuffer + // if we do the padding + private int bytesBuffered; + + // length of key size in bytes; currently only used by AES given its oid + // specification mandates a fixed size of the key + private int fixedKeySize = -1; + + // Indicates whether the underlying PKCS#11 library requires block-sized + // updates during multi-part operations. In such case, we buffer data in + // padBuffer up to a block-size. This may be needed only if padding is + // applied on the Java side. An example of the previous is when the + // CKM_AES_ECB mechanism is used and the PKCS#11 library is NSS. See more + // on JDK-8261355. + private boolean reqBlockUpdates = false; + + P11Cipher(Token token, String algorithm, long mechanism) + throws PKCS11Exception, NoSuchAlgorithmException { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + + String algoParts[] = algorithm.split("/"); + + if (algoParts[0].startsWith("AES")) { + blockSize = 16; + int index = algoParts[0].indexOf('_'); + if (index != -1) { + // should be well-formed since we specify what we support + fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1))/8; + } + keyAlgorithm = "AES"; + } else { + keyAlgorithm = algoParts[0]; + if (keyAlgorithm.equals("RC4") || + keyAlgorithm.equals("ARCFOUR")) { + blockSize = 0; + } else { // DES, DESede, Blowfish + blockSize = 8; + } + } + this.blockMode = + (algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB); + String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding"); + String paddingStr = + (algoParts.length > 2 ? algoParts[2] : defPadding); + try { + engineSetPadding(paddingStr); + } catch (NoSuchPaddingException nspe) { + // should not happen + throw new ProviderException(nspe); + } + } + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + // Disallow change of mode for now since currently it's explicitly + // defined in transformation strings + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + + private int parseMode(String mode) throws NoSuchAlgorithmException { + mode = mode.toUpperCase(Locale.ENGLISH); + int result; + if (mode.equals("ECB")) { + result = MODE_ECB; + } else if (mode.equals("CBC")) { + if (blockSize == 0) { + throw new NoSuchAlgorithmException + ("CBC mode not supported with stream ciphers"); + } + result = MODE_CBC; + } else if (mode.equals("CTR")) { + result = MODE_CTR; + } else { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + return result; + } + + // see JCE spec + protected void engineSetPadding(String padding) + throws NoSuchPaddingException { + paddingObj = null; + padBuffer = null; + padding = padding.toUpperCase(Locale.ENGLISH); + if (padding.equals("NOPADDING")) { + paddingType = PAD_NONE; + } else if (padding.equals("PKCS5PADDING")) { + if (this.blockMode == MODE_CTR) { + throw new NoSuchPaddingException + ("PKCS#5 padding not supported with CTR mode"); + } + paddingType = PAD_PKCS5; + if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD && + mechanism != CKM_AES_CBC_PAD) { + // no native padding support; use our own padding impl + paddingObj = new PKCS5Padding(blockSize); + padBuffer = new byte[blockSize]; + char[] tokenLabel = token.tokenInfo.label; + // NSS requires block-sized updates in multi-part operations. + reqBlockUpdates = ((tokenLabel[0] == 'N' && tokenLabel[1] == 'S' + && tokenLabel[2] == 'S') ? true : false); + } + } else { + throw new NoSuchPaddingException("Unsupported padding " + padding); + } + } + + // see JCE spec + protected int engineGetBlockSize() { + return blockSize; + } + + // see JCE spec + protected int engineGetOutputSize(int inputLen) { + return doFinalLength(inputLen); + } + + // see JCE spec + protected byte[] engineGetIV() { + return (iv == null) ? null : iv.clone(); + } + + // see JCE spec + protected AlgorithmParameters engineGetParameters() { + if (iv == null) { + return null; + } + IvParameterSpec ivSpec = new IvParameterSpec(iv); + try { + AlgorithmParameters params = + AlgorithmParameters.getInstance(keyAlgorithm, + P11Util.getSunJceProvider()); + params.init(ivSpec); + return params; + } catch (GeneralSecurityException e) { + // NoSuchAlgorithmException, NoSuchProviderException + // InvalidParameterSpecException + throw new ProviderException("Could not encode parameters", e); + } + } + + // see JCE spec + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException { + try { + implInit(opmode, key, null, random); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidKeyException("init() failed", e); + } + } + + // see JCE spec + protected void engineInit(int opmode, Key key, + AlgorithmParameterSpec params, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + byte[] ivValue; + if (params != null) { + if (params instanceof IvParameterSpec == false) { + throw new InvalidAlgorithmParameterException + ("Only IvParameterSpec supported"); + } + IvParameterSpec ivSpec = (IvParameterSpec) params; + ivValue = ivSpec.getIV(); + } else { + ivValue = null; + } + implInit(opmode, key, ivValue, random); + } + + // see JCE spec + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + byte[] ivValue; + if (params != null) { + try { + IvParameterSpec ivSpec = + params.getParameterSpec(IvParameterSpec.class); + ivValue = ivSpec.getIV(); + } catch (InvalidParameterSpecException e) { + throw new InvalidAlgorithmParameterException + ("Could not decode IV", e); + } + } else { + ivValue = null; + } + implInit(opmode, key, ivValue, random); + } + + // actual init() implementation + private void implInit(int opmode, Key key, byte[] iv, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + reset(true); + if (fixedKeySize != -1 && + ((key instanceof P11Key) ? ((P11Key) key).length() >> 3 : + key.getEncoded().length) != fixedKeySize) { + throw new InvalidKeyException("Key size is invalid"); + } + switch (opmode) { + case Cipher.ENCRYPT_MODE: + encrypt = true; + break; + case Cipher.DECRYPT_MODE: + encrypt = false; + break; + default: + throw new InvalidAlgorithmParameterException + ("Unsupported mode: " + opmode); + } + if (blockMode == MODE_ECB) { // ECB or stream cipher + if (iv != null) { + if (blockSize == 0) { + throw new InvalidAlgorithmParameterException + ("IV not used with stream ciphers"); + } else { + throw new InvalidAlgorithmParameterException + ("IV not used in ECB mode"); + } + } + } else { // MODE_CBC or MODE_CTR + if (iv == null) { + if (encrypt == false) { + String exMsg = + (blockMode == MODE_CBC ? + "IV must be specified for decryption in CBC mode" : + "IV must be specified for decryption in CTR mode"); + throw new InvalidAlgorithmParameterException(exMsg); + } + // generate random IV + if (random == null) { + random = JCAUtil.getSecureRandom(); + } + iv = new byte[blockSize]; + random.nextBytes(iv); + } else { + if (iv.length != blockSize) { + throw new InvalidAlgorithmParameterException + ("IV length must match block size"); + } + } + } + this.iv = iv; + p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm); + try { + initialize(); + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not initialize cipher", e); + } + } + + // reset the states to the pre-initialized values + // need to be called after doFinal or prior to re-init + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + + try { + if (session == null) { + return; + } + + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + bytesBuffered = 0; + padBufferLen = 0; + } + } + + private void cancelOperation() { + token.ensureValid(); + // cancel operation by finishing it; avoid killSession as some + // hardware vendors may require re-login + try { + int bufLen = doFinalLength(0); + byte[] buffer = new byte[bufLen]; + if (encrypt) { + token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen); + } else { + token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen); + } + } catch (PKCS11Exception e) { + if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { + // Cancel Operation may be invoked after an error on a PKCS#11 + // call. If the operation inside the token was already cancelled, + // do not fail here. This is part of a defensive mechanism for + // PKCS#11 libraries that do not strictly follow the standard. + return; + } + if (encrypt) { + throw new ProviderException("Cancel failed", e); + } + // ignore failure for decryption + } + } + + private void ensureInitialized() throws PKCS11Exception { + if (!initialized) { + initialize(); + } + } + + private void initialize() throws PKCS11Exception { + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without" + + " calling engineInit first"); + } + token.ensureValid(); + long p11KeyID = p11Key.getKeyID(); + try { + if (session == null) { + session = token.getOpSession(); + } + CK_MECHANISM mechParams = (blockMode == MODE_CTR? + new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : + new CK_MECHANISM(mechanism, iv)); + if (encrypt) { + token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID); + } else { + token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID); + } + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw e; + } + initialized = true; + bytesBuffered = 0; + padBufferLen = 0; + } + + // if update(inLen) is called, how big does the output buffer have to be? + private int updateLength(int inLen) { + if (inLen <= 0) { + return 0; + } + + int result = inLen + bytesBuffered; + if (blockSize != 0 && blockMode != MODE_CTR) { + // minus the number of bytes in the last incomplete block. + result -= (result & (blockSize - 1)); + } + return result; + } + + // if doFinal(inLen) is called, how big does the output buffer have to be? + private int doFinalLength(int inLen) { + if (inLen < 0) { + return 0; + } + + int result = inLen + bytesBuffered; + if (blockSize != 0 && encrypt && paddingType != PAD_NONE) { + // add the number of bytes to make the last block complete. + result += (blockSize - (result & (blockSize - 1))); + } + return result; + } + + // see JCE spec + protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { + try { + byte[] out = new byte[updateLength(inLen)]; + int n = engineUpdate(in, inOfs, inLen, out, 0); + return P11Util.convert(out, 0, n); + } catch (ShortBufferException e) { + // convert since the output length is calculated by updateLength() + throw new ProviderException(e); + } + } + + // see JCE spec + protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws ShortBufferException { + int outLen = out.length - outOfs; + return implUpdate(in, inOfs, inLen, out, outOfs, outLen); + } + + // see JCE spec + @Override + protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) + throws ShortBufferException { + return implUpdate(inBuffer, outBuffer); + } + + // see JCE spec + protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) + throws IllegalBlockSizeException, BadPaddingException { + try { + byte[] out = new byte[doFinalLength(inLen)]; + int n = engineDoFinal(in, inOfs, inLen, out, 0); + return P11Util.convert(out, 0, n); + } catch (ShortBufferException e) { + // convert since the output length is calculated by doFinalLength() + throw new ProviderException(e); + } + } + + // see JCE spec + protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + int n = 0; + if ((inLen != 0) && (in != null)) { + n = engineUpdate(in, inOfs, inLen, out, outOfs); + outOfs += n; + } + n += implDoFinal(out, outOfs, out.length - outOfs); + return n; + } + + // see JCE spec + @Override + protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + int n = engineUpdate(inBuffer, outBuffer); + n += implDoFinal(outBuffer); + return n; + } + + private int implUpdate(byte[] in, int inOfs, int inLen, + byte[] out, int outOfs, int outLen) throws ShortBufferException { + if (outLen < updateLength(inLen)) { + throw new ShortBufferException(); + } + try { + ensureInitialized(); + int k = 0; + int newPadBufferLen = 0; + if (paddingObj != null && (!encrypt || reqBlockUpdates)) { + if (padBufferLen != 0) { + if (padBufferLen != padBuffer.length) { + int bufCapacity = padBuffer.length - padBufferLen; + if (inLen > bufCapacity) { + bufferInputBytes(in, inOfs, bufCapacity); + inOfs += bufCapacity; + inLen -= bufCapacity; + } else { + bufferInputBytes(in, inOfs, inLen); + return 0; + } + } + if (encrypt) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); + } else { + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); + } + padBufferLen = 0; + } + newPadBufferLen = inLen & (blockSize - 1); + if (!encrypt && newPadBufferLen == 0) { + // While decrypting with implUpdate, the last encrypted block + // is always held in a buffer. If it's the final one (unknown + // at this point), it may contain padding bytes and need further + // processing. In implDoFinal (where we know it's the final one) + // the buffer is decrypted, unpadded and returned. + newPadBufferLen = padBuffer.length; + } + inLen -= newPadBufferLen; + } + if (inLen > 0) { + if (encrypt) { + k += token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, + inLen, 0, out, (outOfs + k), (outLen - k)); + } else { + k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs, + inLen, 0, out, (outOfs + k), (outLen - k)); + } + } + // update 'padBuffer' if using our own padding impl. + if (paddingObj != null && newPadBufferLen > 0) { + bufferInputBytes(in, inOfs + inLen, newPadBufferLen); + } + bytesBuffered += (inLen - k); + return k; + } catch (PKCS11Exception e) { + if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) { + throw (ShortBufferException) + (new ShortBufferException().initCause(e)); + } + // Some implementations such as the NSS Software Token do not + // cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate + // failure (as required by the PKCS#11 standard). See JDK-8258833 + // for further information. + reset(true); + throw new ProviderException("update() failed", e); + } + } + + private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) + throws ShortBufferException { + int inLen = inBuffer.remaining(); + if (inLen <= 0) { + return 0; + } + + int outLen = outBuffer.remaining(); + if (outLen < updateLength(inLen)) { + throw new ShortBufferException(); + } + int origPos = inBuffer.position(); + try { + ensureInitialized(); + + long inAddr = 0; + int inOfs = 0; + byte[] inArray = null; + + if (inBuffer instanceof DirectBuffer) { + inAddr = ((DirectBuffer) inBuffer).address(); + inOfs = origPos; + } else if (inBuffer.hasArray()) { + inArray = inBuffer.array(); + inOfs = (origPos + inBuffer.arrayOffset()); + } + + long outAddr = 0; + int outOfs = 0; + byte[] outArray = null; + if (outBuffer instanceof DirectBuffer) { + outAddr = ((DirectBuffer) outBuffer).address(); + outOfs = outBuffer.position(); + } else { + if (outBuffer.hasArray()) { + outArray = outBuffer.array(); + outOfs = (outBuffer.position() + outBuffer.arrayOffset()); + } else { + outArray = new byte[outLen]; + } + } + + int k = 0; + int newPadBufferLen = 0; + if (paddingObj != null && (!encrypt || reqBlockUpdates)) { + if (padBufferLen != 0) { + if (padBufferLen != padBuffer.length) { + int bufCapacity = padBuffer.length - padBufferLen; + if (inLen > bufCapacity) { + bufferInputBytes(inBuffer, bufCapacity); + inOfs += bufCapacity; + inLen -= bufCapacity; + } else { + bufferInputBytes(inBuffer, inLen); + return 0; + } + } + if (encrypt) { + k = token.p11.C_EncryptUpdate(session.id(), 0, + padBuffer, 0, padBufferLen, outAddr, outArray, + outOfs, outLen); + } else { + k = token.p11.C_DecryptUpdate(session.id(), 0, + padBuffer, 0, padBufferLen, outAddr, outArray, + outOfs, outLen); + } + padBufferLen = 0; + } + newPadBufferLen = inLen & (blockSize - 1); + if (!encrypt && newPadBufferLen == 0) { + // While decrypting with implUpdate, the last encrypted block + // is always held in a buffer. If it's the final one (unknown + // at this point), it may contain padding bytes and need further + // processing. In implDoFinal (where we know it's the final one) + // the buffer is decrypted, unpadded and returned. + newPadBufferLen = padBuffer.length; + } + inLen -= newPadBufferLen; + } + if (inLen > 0) { + if (inAddr == 0 && inArray == null) { + inArray = new byte[inLen]; + inBuffer.get(inArray); + } else { + inBuffer.position(inBuffer.position() + inLen); + } + if (encrypt) { + k += token.p11.C_EncryptUpdate(session.id(), inAddr, + inArray, inOfs, inLen, outAddr, outArray, + (outOfs + k), (outLen - k)); + } else { + k += token.p11.C_DecryptUpdate(session.id(), inAddr, + inArray, inOfs, inLen, outAddr, outArray, + (outOfs + k), (outLen - k)); + } + } + // update 'padBuffer' if using our own padding impl. + if (paddingObj != null && newPadBufferLen > 0) { + bufferInputBytes(inBuffer, newPadBufferLen); + } + bytesBuffered += (inLen - k); + if (!(outBuffer instanceof DirectBuffer) && + !outBuffer.hasArray()) { + outBuffer.put(outArray, outOfs, k); + } else { + outBuffer.position(outBuffer.position() + k); + } + return k; + } catch (PKCS11Exception e) { + // Reset input buffer to its original position for + inBuffer.position(origPos); + if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) { + throw (ShortBufferException) + (new ShortBufferException().initCause(e)); + } + // Some implementations such as the NSS Software Token do not + // cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate + // failure (as required by the PKCS#11 standard). See JDK-8258833 + // for further information. + reset(true); + throw new ProviderException("update() failed", e); + } + } + + private int implDoFinal(byte[] out, int outOfs, int outLen) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + int requiredOutLen = doFinalLength(0); + if (outLen < requiredOutLen) { + throw new ShortBufferException(); + } + boolean doCancel = true; + try { + ensureInitialized(); + int k = 0; + if (encrypt) { + if (paddingObj != null) { + int startOff = 0; + if (reqBlockUpdates) { + // call C_EncryptUpdate first if the padBuffer is full + // to make room for padding bytes + if (padBufferLen == padBuffer.length) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); + } else { + startOff = padBufferLen; + } + } + int actualPadLen = paddingObj.setPaddingBytes(padBuffer, + startOff, requiredOutLen - bytesBuffered); + k += token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, startOff + actualPadLen, + 0, out, outOfs + k, outLen - k); + } + // Some implementations such as the NSS Software Token do not + // cancel the operation upon a C_EncryptUpdate failure (as + // required by the PKCS#11 standard). Cancel is not needed + // only after this point. See JDK-8258833 for further + // information. + doCancel = false; + k += token.p11.C_EncryptFinal(session.id(), + 0, out, (outOfs + k), (outLen - k)); + } else { + // Special handling to match SunJCE provider behavior + if (bytesBuffered == 0 && padBufferLen == 0) { + return 0; + } + if (paddingObj != null) { + if (padBufferLen != 0) { + k = token.p11.C_DecryptUpdate(session.id(), 0, + padBuffer, 0, padBufferLen, 0, padBuffer, 0, + padBuffer.length); + } + // Some implementations such as the NSS Software Token do not + // cancel the operation upon a C_DecryptUpdate failure (as + // required by the PKCS#11 standard). Cancel is not needed + // only after this point. See JDK-8258833 for further + // information. + doCancel = false; + k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k, + padBuffer.length - k); + + int actualPadLen = paddingObj.unpad(padBuffer, k); + k -= actualPadLen; + System.arraycopy(padBuffer, 0, out, outOfs, k); + } else { + doCancel = false; + k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, + outLen); + } + } + return k; + } catch (PKCS11Exception e) { + handleException(e); + throw new ProviderException("doFinal() failed", e); + } finally { + reset(doCancel); + } + } + + private int implDoFinal(ByteBuffer outBuffer) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException { + int outLen = outBuffer.remaining(); + int requiredOutLen = doFinalLength(0); + if (outLen < requiredOutLen) { + throw new ShortBufferException(); + } + + boolean doCancel = true; + try { + ensureInitialized(); + + long outAddr = 0; + byte[] outArray = null; + int outOfs = 0; + if (outBuffer instanceof DirectBuffer) { + outAddr = ((DirectBuffer) outBuffer).address(); + outOfs = outBuffer.position(); + } else { + if (outBuffer.hasArray()) { + outArray = outBuffer.array(); + outOfs = outBuffer.position() + outBuffer.arrayOffset(); + } else { + outArray = new byte[outLen]; + } + } + + int k = 0; + + if (encrypt) { + if (paddingObj != null) { + int startOff = 0; + if (reqBlockUpdates) { + // call C_EncryptUpdate first if the padBuffer is full + // to make room for padding bytes + if (padBufferLen == padBuffer.length) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + outAddr, outArray, outOfs, outLen); + } else { + startOff = padBufferLen; + } + } + int actualPadLen = paddingObj.setPaddingBytes(padBuffer, + startOff, requiredOutLen - bytesBuffered); + k += token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, startOff + actualPadLen, + outAddr, outArray, outOfs + k, outLen - k); + } + // Some implementations such as the NSS Software Token do not + // cancel the operation upon a C_EncryptUpdate failure (as + // required by the PKCS#11 standard). Cancel is not needed + // only after this point. See JDK-8258833 for further + // information. + doCancel = false; + k += token.p11.C_EncryptFinal(session.id(), + outAddr, outArray, (outOfs + k), (outLen - k)); + } else { + // Special handling to match SunJCE provider behavior + if (bytesBuffered == 0 && padBufferLen == 0) { + return 0; + } + + if (paddingObj != null) { + if (padBufferLen != 0) { + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, padBuffer, 0, padBuffer.length); + padBufferLen = 0; + } + // Some implementations such as the NSS Software Token do not + // cancel the operation upon a C_DecryptUpdate failure (as + // required by the PKCS#11 standard). Cancel is not needed + // only after this point. See JDK-8258833 for further + // information. + doCancel = false; + k += token.p11.C_DecryptFinal(session.id(), + 0, padBuffer, k, padBuffer.length - k); + + int actualPadLen = paddingObj.unpad(padBuffer, k); + k -= actualPadLen; + outArray = padBuffer; + outOfs = 0; + } else { + doCancel = false; + k = token.p11.C_DecryptFinal(session.id(), + outAddr, outArray, outOfs, outLen); + } + } + if ((!encrypt && paddingObj != null) || + (!(outBuffer instanceof DirectBuffer) && + !outBuffer.hasArray())) { + outBuffer.put(outArray, outOfs, k); + } else { + outBuffer.position(outBuffer.position() + k); + } + return k; + } catch (PKCS11Exception e) { + handleException(e); + throw new ProviderException("doFinal() failed", e); + } finally { + reset(doCancel); + } + } + + private void handleException(PKCS11Exception e) + throws ShortBufferException, IllegalBlockSizeException { + long errorCode = e.getErrorCode(); + if (errorCode == CKR_BUFFER_TOO_SMALL) { + throw (ShortBufferException) + (new ShortBufferException().initCause(e)); + } else if (errorCode == CKR_DATA_LEN_RANGE || + errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) { + throw (IllegalBlockSizeException) + (new IllegalBlockSizeException(e.toString()).initCause(e)); + } + } + + // see JCE spec + protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, + InvalidKeyException { + // XXX key wrapping + throw new UnsupportedOperationException("engineWrap()"); + } + + // see JCE spec + protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException { + // XXX key unwrapping + throw new UnsupportedOperationException("engineUnwrap()"); + } + + // see JCE spec + @Override + protected int engineGetKeySize(Key key) throws InvalidKeyException { + int n = P11SecretKeyFactory.convertKey + (token, key, keyAlgorithm).length(); + return n; + } + + private final void bufferInputBytes(byte[] in, int inOfs, int len) { + System.arraycopy(in, inOfs, padBuffer, padBufferLen, len); + padBufferLen += len; + bytesBuffered += len; + } + + private final void bufferInputBytes(ByteBuffer inBuffer, int len) { + inBuffer.get(padBuffer, padBufferLen, len); + padBufferLen += len; + bytesBuffered += len; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11DHKeyFactory.java b/src/main/java/com/sunyard/security/pkcs11/P11DHKeyFactory.java new file mode 100644 index 0000000..861dd3a --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11DHKeyFactory.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; + +import java.security.*; +import java.security.spec.*; + +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * DH KeyFactory implementation. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11DHKeyFactory extends P11KeyFactory { + + P11DHKeyFactory(Token token, String algorithm) { + super(token, algorithm); + } + + PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { + try { + if (key instanceof DHPublicKey) { + DHPublicKey dhKey = (DHPublicKey)key; + DHParameterSpec params = dhKey.getParams(); + return generatePublic( + dhKey.getY(), + params.getP(), + params.getG() + ); + } else if ("X.509".equals(key.getFormat())) { + // let SunJCE provider parse for us, then recurse + try { + KeyFactory factory = implGetSoftwareFactory(); + key = (PublicKey)factory.translateKey(key); + return implTranslatePublicKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeyException("Could not translate key", e); + } + } else { + throw new InvalidKeyException("PublicKey must be instance " + + "of DHPublicKey or have X.509 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create DH public key", e); + } + } + + PrivateKey implTranslatePrivateKey(PrivateKey key) + throws InvalidKeyException { + try { + if (key instanceof DHPrivateKey) { + DHPrivateKey dhKey = (DHPrivateKey)key; + DHParameterSpec params = dhKey.getParams(); + return generatePrivate( + dhKey.getX(), + params.getP(), + params.getG() + ); + } else if ("PKCS#8".equals(key.getFormat())) { + // let SunJCE provider parse for us, then recurse + try { + KeyFactory factory = implGetSoftwareFactory(); + key = (PrivateKey)factory.translateKey(key); + return implTranslatePrivateKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeyException("Could not translate key", e); + } + } else { + throw new InvalidKeyException("PrivateKey must be instance " + + "of DHPrivateKey or have PKCS#8 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create DH private key", e); + } + } + + // see JCA spec + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof X509EncodedKeySpec) { + try { + KeyFactory factory = implGetSoftwareFactory(); + PublicKey key = factory.generatePublic(keySpec); + return implTranslatePublicKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException + ("Could not create DH public key", e); + } + } + if (keySpec instanceof DHPublicKeySpec == false) { + throw new InvalidKeySpecException("Only DHPublicKeySpec and " + + "X509EncodedKeySpec supported for DH public keys"); + } + try { + DHPublicKeySpec ds = (DHPublicKeySpec)keySpec; + return generatePublic( + ds.getY(), + ds.getP(), + ds.getG() + ); + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException + ("Could not create DH public key", e); + } + } + + // see JCA spec + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof PKCS8EncodedKeySpec) { + try { + KeyFactory factory = implGetSoftwareFactory(); + PrivateKey key = factory.generatePrivate(keySpec); + return implTranslatePrivateKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException + ("Could not create DH private key", e); + } + } + if (keySpec instanceof DHPrivateKeySpec == false) { + throw new InvalidKeySpecException("Only DHPrivateKeySpec and " + + "PKCS8EncodedKeySpec supported for DH private keys"); + } + try { + DHPrivateKeySpec ds = (DHPrivateKeySpec)keySpec; + return generatePrivate( + ds.getX(), + ds.getP(), + ds.getG() + ); + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException + ("Could not create DH private key", e); + } + } + + private PublicKey generatePublic(BigInteger y, BigInteger p, BigInteger g) + throws PKCS11Exception { + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH), + new CK_ATTRIBUTE(CKA_VALUE, y), + new CK_ATTRIBUTE(CKA_PRIME, p), + new CK_ATTRIBUTE(CKA_BASE, g), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PUBLIC_KEY, CKK_DH, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.publicKey + (session, keyID, "DH", p.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + private PrivateKey generatePrivate(BigInteger x, BigInteger p, + BigInteger g) throws PKCS11Exception { + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH), + new CK_ATTRIBUTE(CKA_VALUE, x), + new CK_ATTRIBUTE(CKA_PRIME, p), + new CK_ATTRIBUTE(CKA_BASE, g), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PRIVATE_KEY, CKK_DH, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.privateKey + (session, keyID, "DH", p.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + T implGetPublicKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(DHPublicKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new DHPublicKeySpec( + attributes[0].getBigInteger(), + attributes[1].getBigInteger(), + attributes[2].getBigInteger() + ); + return keySpec.cast(spec); + } else { // X.509 handled in superclass + throw new InvalidKeySpecException("Only DHPublicKeySpec and " + + "X509EncodedKeySpec supported for DH public keys"); + } + } + + T implGetPrivateKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(DHPrivateKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new DHPrivateKeySpec( + attributes[0].getBigInteger(), + attributes[1].getBigInteger(), + attributes[2].getBigInteger() + ); + return keySpec.cast(spec); + } else { // PKCS#8 handled in superclass + throw new InvalidKeySpecException("Only DHPrivateKeySpec " + + "and PKCS8EncodedKeySpec supported for DH private keys"); + } + } + + KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { + return KeyFactory.getInstance("DH", P11Util.getSunJceProvider()); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11DSAKeyFactory.java b/src/main/java/com/sunyard/security/pkcs11/P11DSAKeyFactory.java new file mode 100644 index 0000000..7c3e2b9 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11DSAKeyFactory.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; + +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * DSA KeyFactory implementation. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11DSAKeyFactory extends P11KeyFactory { + + P11DSAKeyFactory(Token token, String algorithm) { + super(token, algorithm); + } + + PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { + try { + if (key instanceof DSAPublicKey) { + DSAPublicKey dsaKey = (DSAPublicKey)key; + DSAParams params = dsaKey.getParams(); + return generatePublic( + dsaKey.getY(), + params.getP(), + params.getQ(), + params.getG() + ); + } else if ("X.509".equals(key.getFormat())) { + // let Sun provider parse for us, then recurse + byte[] encoded = key.getEncoded(); + key = new sun.security.provider.DSAPublicKey(encoded); + return implTranslatePublicKey(key); + } else { + throw new InvalidKeyException("PublicKey must be instance " + + "of DSAPublicKey or have X.509 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create DSA public key", e); + } + } + + PrivateKey implTranslatePrivateKey(PrivateKey key) + throws InvalidKeyException { + try { + if (key instanceof DSAPrivateKey) { + DSAPrivateKey dsaKey = (DSAPrivateKey)key; + DSAParams params = dsaKey.getParams(); + return generatePrivate( + dsaKey.getX(), + params.getP(), + params.getQ(), + params.getG() + ); + } else if ("PKCS#8".equals(key.getFormat())) { + // let Sun provider parse for us, then recurse + byte[] encoded = key.getEncoded(); + key = new sun.security.provider.DSAPrivateKey(encoded); + return implTranslatePrivateKey(key); + } else { + throw new InvalidKeyException("PrivateKey must be instance " + + "of DSAPrivateKey or have PKCS#8 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create DSA private key", e); + } + } + + // see JCA spec + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof X509EncodedKeySpec) { + try { + byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded(); + PublicKey key = new sun.security.provider.DSAPublicKey(encoded); + return implTranslatePublicKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException + ("Could not create DSA public key", e); + } + } + if (keySpec instanceof DSAPublicKeySpec == false) { + throw new InvalidKeySpecException("Only DSAPublicKeySpec and " + + "X509EncodedKeySpec supported for DSA public keys"); + } + try { + DSAPublicKeySpec ds = (DSAPublicKeySpec)keySpec; + return generatePublic( + ds.getY(), + ds.getP(), + ds.getQ(), + ds.getG() + ); + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException + ("Could not create DSA public key", e); + } + } + + // see JCA spec + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof PKCS8EncodedKeySpec) { + try { + byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); + PrivateKey key = new sun.security.provider.DSAPrivateKey(encoded); + return implTranslatePrivateKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException + ("Could not create DSA private key", e); + } + } + if (keySpec instanceof DSAPrivateKeySpec == false) { + throw new InvalidKeySpecException("Only DSAPrivateKeySpec and " + + "PKCS8EncodedKeySpec supported for DSA private keys"); + } + try { + DSAPrivateKeySpec ds = (DSAPrivateKeySpec)keySpec; + return generatePrivate( + ds.getX(), + ds.getP(), + ds.getQ(), + ds.getG() + ); + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException + ("Could not create DSA private key", e); + } + } + + private PublicKey generatePublic(BigInteger y, BigInteger p, BigInteger q, + BigInteger g) throws PKCS11Exception { + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DSA), + new CK_ATTRIBUTE(CKA_VALUE, y), + new CK_ATTRIBUTE(CKA_PRIME, p), + new CK_ATTRIBUTE(CKA_SUBPRIME, q), + new CK_ATTRIBUTE(CKA_BASE, g), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PUBLIC_KEY, CKK_DSA, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.publicKey + (session, keyID, "DSA", p.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + private PrivateKey generatePrivate(BigInteger x, BigInteger p, + BigInteger q, BigInteger g) throws PKCS11Exception { + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DSA), + new CK_ATTRIBUTE(CKA_VALUE, x), + new CK_ATTRIBUTE(CKA_PRIME, p), + new CK_ATTRIBUTE(CKA_SUBPRIME, q), + new CK_ATTRIBUTE(CKA_BASE, g), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PRIVATE_KEY, CKK_DSA, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.privateKey + (session, keyID, "DSA", p.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + T implGetPublicKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(DSAPublicKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_SUBPRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new DSAPublicKeySpec( + attributes[0].getBigInteger(), + attributes[1].getBigInteger(), + attributes[2].getBigInteger(), + attributes[3].getBigInteger() + ); + return keySpec.cast(spec); + } else { // X.509 handled in superclass + throw new InvalidKeySpecException("Only DSAPublicKeySpec and " + + "X509EncodedKeySpec supported for DSA public keys"); + } + } + + T implGetPrivateKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(DSAPrivateKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_SUBPRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new DSAPrivateKeySpec( + attributes[0].getBigInteger(), + attributes[1].getBigInteger(), + attributes[2].getBigInteger(), + attributes[3].getBigInteger() + ); + return keySpec.cast(spec); + } else { // PKCS#8 handled in superclass + throw new InvalidKeySpecException("Only DSAPrivateKeySpec " + + "and PKCS8EncodedKeySpec supported for DSA private keys"); + } + } + + KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { + return KeyFactory.getInstance("DSA", P11Util.getSunProvider()); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11Digest.java b/src/main/java/com/sunyard/security/pkcs11/P11Digest.java new file mode 100644 index 0000000..9973a05 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11Digest.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; +import java.nio.ByteBuffer; + +import java.security.*; + +import javax.crypto.SecretKey; + +import sun.nio.ch.DirectBuffer; + +//import sun.security.util.MessageDigestSpi2; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * MessageDigest implementation class. This class currently supports + * MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512. + * + * Note that many digest operations are on fairly small amounts of data + * (less than 100 bytes total). For example, the 2nd hashing in HMAC or + * the PRF in TLS. In order to speed those up, we use some buffering to + * minimize number of the Java->native transitions. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11Digest extends MessageDigestSpi implements Cloneable, + MessageDigestSpi2 { + + /* fields initialized, no session acquired */ + private final static int S_BLANK = 1; + + /* data in buffer, session acquired, but digest not initialized */ + private final static int S_BUFFERED = 2; + + /* session initialized for digesting */ + private final static int S_INIT = 3; + + private final static int BUFFER_SIZE = 96; + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id object + private final CK_MECHANISM mechanism; + + // length of the digest in bytes + private final int digestLength; + + // associated session, if any + private Session session; + + // current state, one of S_* above + private int state; + + // buffer to reduce number of JNI calls + private byte[] buffer; + + // offset into the buffer + private int bufOfs; + + P11Digest(Token token, String algorithm, long mechanism) { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = new CK_MECHANISM(mechanism); + switch ((int)mechanism) { + case (int)CKM_MD2: + case (int)CKM_MD5: + digestLength = 16; + break; + case (int)CKM_SHA_1: + digestLength = 20; + break; + case (int)CKM_SHA224: + case (int)CKM_SHA512_224: + digestLength = 28; + break; + case (int)CKM_SHA256: + case (int)CKM_SHA512_256: + digestLength = 32; + break; + case (int)CKM_SHA384: + digestLength = 48; + break; + case (int)CKM_SHA512: + digestLength = 64; + break; + default: + throw new ProviderException("Unknown mechanism: " + mechanism); + } + buffer = new byte[BUFFER_SIZE]; + state = S_BLANK; + } + + // see JCA spec + protected int engineGetDigestLength() { + return digestLength; + } + + private void fetchSession() { + token.ensureValid(); + if (state == S_BLANK) { + try { + session = token.getOpSession(); + state = S_BUFFERED; + } catch (PKCS11Exception e) { + throw new ProviderException("No more session available", e); + } + } + } + + // see JCA spec + protected void engineReset() { + token.ensureValid(); + + if (session != null) { + if (state == S_INIT && token.explicitCancel == true + && session.hasObjects() == false) { + session = token.killSession(session); + } else { + session = token.releaseSession(session); + } + } + state = S_BLANK; + bufOfs = 0; + } + + // see JCA spec + protected byte[] engineDigest() { + try { + byte[] digest = new byte[digestLength]; + int n = engineDigest(digest, 0, digestLength); + return digest; + } catch (DigestException e) { + throw new ProviderException("internal error", e); + } + } + + // see JCA spec + protected int engineDigest(byte[] digest, int ofs, int len) + throws DigestException { + if (len < digestLength) { + throw new DigestException("Length must be at least " + + digestLength); + } + + fetchSession(); + try { + int n; + if (state == S_BUFFERED) { + n = token.p11.C_DigestSingle(session.id(), mechanism, buffer, 0, + bufOfs, digest, ofs, len); + bufOfs = 0; + } else { + if (bufOfs != 0) { + token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, + bufOfs); + bufOfs = 0; + } + n = token.p11.C_DigestFinal(session.id(), digest, ofs, len); + } + if (n != digestLength) { + throw new ProviderException("internal digest length error"); + } + return n; + } catch (PKCS11Exception e) { + throw new ProviderException("digest() failed", e); + } finally { + engineReset(); + } + } + + // see JCA spec + protected void engineUpdate(byte in) { + byte[] temp = { in }; + engineUpdate(temp, 0, 1); + } + + // see JCA spec + protected void engineUpdate(byte[] in, int ofs, int len) { + if (len <= 0) { + return; + } + + fetchSession(); + try { + if (state == S_BUFFERED) { + token.p11.C_DigestInit(session.id(), mechanism); + state = S_INIT; + } + if ((bufOfs != 0) && (bufOfs + len > buffer.length)) { + // process the buffered data + token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); + bufOfs = 0; + } + if (bufOfs + len > buffer.length) { + // process the new data + token.p11.C_DigestUpdate(session.id(), 0, in, ofs, len); + } else { + // buffer the new data + System.arraycopy(in, ofs, buffer, bufOfs, len); + bufOfs += len; + } + } catch (PKCS11Exception e) { + engineReset(); + throw new ProviderException("update() failed", e); + } + } + + // Called by SunJSSE via reflection during the SSL 3.0 handshake if + // the master secret is sensitive. + // Note: Change to protected after this method is moved from + // sun.security.util.MessageSpi2 interface to + // java.security.MessageDigestSpi class + public void engineUpdate(SecretKey key) throws InvalidKeyException { + // SunJSSE calls this method only if the key does not have a RAW + // encoding, i.e. if it is sensitive. Therefore, no point in calling + // SecretKeyFactory to try to convert it. Just verify it ourselves. + if (key instanceof P11Key == false) { + throw new InvalidKeyException("Not a P11Key: " + key); + } + P11Key p11Key = (P11Key)key; + if (p11Key.token != token) { + throw new InvalidKeyException("Not a P11Key of this provider: " + + key); + } + + fetchSession(); + long p11KeyID = p11Key.getKeyID(); + try { + if (state == S_BUFFERED) { + token.p11.C_DigestInit(session.id(), mechanism); + state = S_INIT; + } + + if (bufOfs != 0) { + token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); + bufOfs = 0; + } + token.p11.C_DigestKey(session.id(), p11KeyID); + } catch (PKCS11Exception e) { + engineReset(); + throw new ProviderException("update(SecretKey) failed", e); + } finally { + p11Key.releaseKeyID(); + } + } + + // see JCA spec + protected void engineUpdate(ByteBuffer byteBuffer) { + int len = byteBuffer.remaining(); + if (len <= 0) { + return; + } + + if (byteBuffer instanceof DirectBuffer == false) { + super.engineUpdate(byteBuffer); + return; + } + + fetchSession(); + long addr = ((DirectBuffer)byteBuffer).address(); + int ofs = byteBuffer.position(); + try { + if (state == S_BUFFERED) { + token.p11.C_DigestInit(session.id(), mechanism); + state = S_INIT; + } + if (bufOfs != 0) { + token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); + bufOfs = 0; + } + token.p11.C_DigestUpdate(session.id(), addr + ofs, null, 0, len); + byteBuffer.position(ofs + len); + } catch (PKCS11Exception e) { + engineReset(); + throw new ProviderException("update() failed", e); + } + } + + public Object clone() throws CloneNotSupportedException { + P11Digest copy = (P11Digest) super.clone(); + copy.buffer = buffer.clone(); + try { + if (session != null) { + copy.session = copy.token.getOpSession(); + } + if (state == S_INIT) { + byte[] stateValues = + token.p11.C_GetOperationState(session.id()); + token.p11.C_SetOperationState(copy.session.id(), + stateValues, 0, 0); + } + } catch (PKCS11Exception e) { + throw (CloneNotSupportedException) + (new CloneNotSupportedException(algorithm).initCause(e)); + } + return copy; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11ECDHKeyAgreement.java b/src/main/java/com/sunyard/security/pkcs11/P11ECDHKeyAgreement.java new file mode 100644 index 0000000..e7a9d0d --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11ECDHKeyAgreement.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * KeyAgreement implementation for ECDH. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +final class P11ECDHKeyAgreement extends KeyAgreementSpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private final long mechanism; + + // private key, if initialized + private P11Key privateKey; + + // encoded public point, non-null between doPhase() and generateSecret() only + private byte[] publicValue; + + // length of the secret to be derived + private int secretLen; + + P11ECDHKeyAgreement(Token token, String algorithm, long mechanism) { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + } + + // see JCE spec + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException { + if (key instanceof PrivateKey == false) { + throw new InvalidKeyException + ("Key must be instance of PrivateKey"); + } + privateKey = P11KeyFactory.convertKey(token, key, "EC"); + publicValue = null; + } + + // see JCE spec + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException + ("Parameters not supported"); + } + engineInit(key, random); + } + + // see JCE spec + protected Key engineDoPhase(Key key, boolean lastPhase) + throws InvalidKeyException, IllegalStateException { + if (privateKey == null) { + throw new IllegalStateException("Not initialized"); + } + if (publicValue != null) { + throw new IllegalStateException("Phase already executed"); + } + if (lastPhase == false) { + throw new IllegalStateException + ("Only two party agreement supported, lastPhase must be true"); + } + if (key instanceof ECPublicKey == false) { + throw new InvalidKeyException + ("Key must be a PublicKey with algorithm EC"); + } + ECPublicKey ecKey = (ECPublicKey)key; + int keyLenBits = ecKey.getParams().getCurve().getField().getFieldSize(); + secretLen = (keyLenBits + 7) >> 3; + publicValue = P11ECKeyFactory.getEncodedPublicValue(ecKey); + return null; + } + + // see JCE spec + protected byte[] engineGenerateSecret() throws IllegalStateException { + if ((privateKey == null) || (publicValue == null)) { + throw new IllegalStateException("Not initialized correctly"); + } + Session session = null; + long privKeyID = privateKey.getKeyID(); + try { + session = token.getOpSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET), + }; + CK_ECDH1_DERIVE_PARAMS ckParams = + new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue); + attributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); + long keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, ckParams), privKeyID, + attributes); + attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE) + }; + token.p11.C_GetAttributeValue(session.id(), keyID, attributes); + byte[] secret = attributes[0].getByteArray(); + token.p11.C_DestroyObject(session.id(), keyID); + return secret; + } catch (PKCS11Exception e) { + throw new ProviderException("Could not derive key", e); + } finally { + privateKey.releaseKeyID(); + publicValue = null; + token.releaseSession(session); + } + } + + // see JCE spec + protected int engineGenerateSecret(byte[] sharedSecret, int + offset) throws IllegalStateException, ShortBufferException { + if (offset + secretLen > sharedSecret.length) { + throw new ShortBufferException("Need " + secretLen + + " bytes, only " + (sharedSecret.length - offset) + " available"); + } + byte[] secret = engineGenerateSecret(); + System.arraycopy(secret, 0, sharedSecret, offset, secret.length); + return secret.length; + } + + // see JCE spec + protected SecretKey engineGenerateSecret(String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, + InvalidKeyException { + if (algorithm == null) { + throw new NoSuchAlgorithmException("Algorithm must not be null"); + } + if (algorithm.equals("TlsPremasterSecret") == false) { + throw new NoSuchAlgorithmException + ("Only supported for algorithm TlsPremasterSecret"); + } + return nativeGenerateSecret(algorithm); + } + + private SecretKey nativeGenerateSecret(String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, + InvalidKeyException { + if ((privateKey == null) || (publicValue == null)) { + throw new IllegalStateException("Not initialized correctly"); + } + long keyType = CKK_GENERIC_SECRET; + Session session = null; + long privKeyID = privateKey.getKeyID(); + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + CK_ECDH1_DERIVE_PARAMS ckParams = + new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue); + attributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); + long keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, ckParams), privKeyID, + attributes); + CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE_LEN), + }; + token.p11.C_GetAttributeValue(session.id(), keyID, lenAttributes); + int keyLen = (int)lenAttributes[0].getLong(); + SecretKey key = P11Key.secretKey + (session, keyID, algorithm, keyLen << 3, attributes); + return key; + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not derive key", e); + } finally { + privateKey.releaseKeyID(); + publicValue = null; + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11ECKeyFactory.java b/src/main/java/com/sunyard/security/pkcs11/P11ECKeyFactory.java new file mode 100644 index 0000000..fdb1a1b --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11ECKeyFactory.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +import sun.security.util.DerValue; +import sun.security.util.ECUtil; + +/** + * EC KeyFactory implementation. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +final class P11ECKeyFactory extends P11KeyFactory { + private static Provider sunECprovider; + + private static Provider getSunECProvider() { + if (sunECprovider == null) { + sunECprovider = Security.getProvider("SunEC"); + if (sunECprovider == null) { + throw new RuntimeException("Cannot load SunEC provider"); + } + } + + return sunECprovider; + } + + P11ECKeyFactory(Token token, String algorithm) { + super(token, algorithm); + } + + static ECParameterSpec getECParameterSpec(String name) { + return ECUtil.getECParameterSpec(getSunECProvider(), name); + } + + static ECParameterSpec getECParameterSpec(int keySize) { + return ECUtil.getECParameterSpec(getSunECProvider(), keySize); + } + + // Check that spec is a known supported curve and convert it to our + // ECParameterSpec subclass. If not possible, return null. + static ECParameterSpec getECParameterSpec(ECParameterSpec spec) { + return ECUtil.getECParameterSpec(getSunECProvider(), spec); + } + + static ECParameterSpec decodeParameters(byte[] params) throws IOException { + return ECUtil.getECParameterSpec(getSunECProvider(), params); + } + + static byte[] encodeParameters(ECParameterSpec params) { + return ECUtil.encodeECParameterSpec(getSunECProvider(), params); + } + + static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) throws IOException { + return ECUtil.decodePoint(encoded, curve); + } + + // Used by ECDH KeyAgreement + static byte[] getEncodedPublicValue(PublicKey key) throws InvalidKeyException { + if (key instanceof ECPublicKey) { + ECPublicKey ecKey = (ECPublicKey)key; + ECPoint w = ecKey.getW(); + ECParameterSpec params = ecKey.getParams(); + return ECUtil.encodePoint(w, params.getCurve()); + } else { + // should never occur + throw new InvalidKeyException + ("Key class not yet supported: " + key.getClass().getName()); + } + } + + PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { + try { + if (key instanceof ECPublicKey) { + ECPublicKey ecKey = (ECPublicKey)key; + return generatePublic( + ecKey.getW(), + ecKey.getParams() + ); + } else if ("X.509".equals(key.getFormat())) { + // let Sun provider parse for us, then recurse + byte[] encoded = key.getEncoded(); + + try { + key = P11ECUtil.decodeX509ECPublicKey(encoded); + } catch (InvalidKeySpecException ikse) { + throw new InvalidKeyException(ikse); + } + + return implTranslatePublicKey(key); + } else { + throw new InvalidKeyException("PublicKey must be instance " + + "of ECPublicKey or have X.509 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create EC public key", e); + } + } + + PrivateKey implTranslatePrivateKey(PrivateKey key) + throws InvalidKeyException { + try { + if (key instanceof ECPrivateKey) { + ECPrivateKey ecKey = (ECPrivateKey)key; + return generatePrivate( + ecKey.getS(), + ecKey.getParams() + ); + } else if ("PKCS#8".equals(key.getFormat())) { + // let Sun provider parse for us, then recurse + byte[] encoded = key.getEncoded(); + + try { + key = P11ECUtil.decodePKCS8ECPrivateKey(encoded); + } catch (InvalidKeySpecException ikse) { + throw new InvalidKeyException(ikse); + } + + return implTranslatePrivateKey(key); + } else { + throw new InvalidKeyException("PrivateKey must be instance " + + "of ECPrivateKey or have PKCS#8 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create EC private key", e); + } + } + + // see JCA spec + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof X509EncodedKeySpec) { + try { + byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded(); + PublicKey key = P11ECUtil.decodeX509ECPublicKey(encoded); + return implTranslatePublicKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException + ("Could not create EC public key", e); + } + } + if (keySpec instanceof ECPublicKeySpec == false) { + throw new InvalidKeySpecException("Only ECPublicKeySpec and " + + "X509EncodedKeySpec supported for EC public keys"); + } + try { + ECPublicKeySpec ec = (ECPublicKeySpec)keySpec; + return generatePublic( + ec.getW(), + ec.getParams() + ); + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException + ("Could not create EC public key", e); + } + } + + // see JCA spec + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof PKCS8EncodedKeySpec) { + try { + byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); + PrivateKey key = P11ECUtil.decodePKCS8ECPrivateKey(encoded); + return implTranslatePrivateKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException + ("Could not create EC private key", e); + } + } + if (keySpec instanceof ECPrivateKeySpec == false) { + throw new InvalidKeySpecException("Only ECPrivateKeySpec and " + + "PKCS8EncodedKeySpec supported for EC private keys"); + } + try { + ECPrivateKeySpec ec = (ECPrivateKeySpec)keySpec; + return generatePrivate( + ec.getS(), + ec.getParams() + ); + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException + ("Could not create EC private key", e); + } + } + + private PublicKey generatePublic(ECPoint point, ECParameterSpec params) + throws PKCS11Exception { + byte[] encodedParams = + ECUtil.encodeECParameterSpec(getSunECProvider(), params); + byte[] encodedPoint = + ECUtil.encodePoint(point, params.getCurve()); + + // Check whether the X9.63 encoding of an EC point shall be wrapped + // in an ASN.1 OCTET STRING + if (!token.config.getUseEcX963Encoding()) { + try { + encodedPoint = + new DerValue(DerValue.tag_OctetString, encodedPoint) + .toByteArray(); + } catch (IOException e) { + throw new + IllegalArgumentException("Could not DER encode point", e); + } + } + + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), + new CK_ATTRIBUTE(CKA_EC_POINT, encodedPoint), + new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PUBLIC_KEY, CKK_EC, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.publicKey + (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); + } finally { + token.releaseSession(session); + } + } + + private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params) + throws PKCS11Exception { + byte[] encodedParams = + ECUtil.encodeECParameterSpec(getSunECProvider(), params); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), + new CK_ATTRIBUTE(CKA_VALUE, s), + new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.privateKey + (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); + } finally { + token.releaseSession(session); + } + } + + T implGetPublicKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_EC_POINT), + new CK_ATTRIBUTE(CKA_EC_PARAMS), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); + ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve()); + return keySpec.cast(new ECPublicKeySpec(point, params)); + } catch (IOException e) { + throw new InvalidKeySpecException("Could not parse key", e); + } finally { + key.releaseKeyID(); + } + } else { // X.509 handled in superclass + throw new InvalidKeySpecException("Only ECPublicKeySpec and " + + "X509EncodedKeySpec supported for EC public keys"); + } + } + + T implGetPrivateKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_EC_PARAMS), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); + return keySpec.cast( + new ECPrivateKeySpec(attributes[0].getBigInteger(), params)); + } catch (IOException e) { + throw new InvalidKeySpecException("Could not parse key", e); + } finally { + key.releaseKeyID(); + } + } else { // PKCS#8 handled in superclass + throw new InvalidKeySpecException("Only ECPrivateKeySpec " + + "and PKCS8EncodedKeySpec supported for EC private keys"); + } + } + + KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { + return KeyFactory.getInstance("EC", getSunECProvider()); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11ECUtil.java b/src/main/java/com/sunyard/security/pkcs11/P11ECUtil.java new file mode 100644 index 0000000..9ab35d6 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11ECUtil.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; + +import sun.security.ec.ECPublicKeyImpl; +import sun.security.ec.ECPrivateKeyImpl; +import sun.security.x509.X509Key; + +final class P11ECUtil { + + static ECPublicKey decodeX509ECPublicKey(byte[] encoded) + throws InvalidKeySpecException { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); + + return (ECPublicKey)ECGeneratePublic(keySpec); + } + + static byte[] x509EncodeECPublicKey(ECPoint w, + ECParameterSpec params) throws InvalidKeySpecException { + ECPublicKeySpec keySpec = new ECPublicKeySpec(w, params); + X509Key key = (X509Key)ECGeneratePublic(keySpec); + + return key.getEncoded(); + } + + static ECPrivateKey decodePKCS8ECPrivateKey(byte[] encoded) + throws InvalidKeySpecException { + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); + + return (ECPrivateKey)ECGeneratePrivate(keySpec); + } + + static ECPrivateKey generateECPrivateKey(BigInteger s, + ECParameterSpec params) throws InvalidKeySpecException { + ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, params); + + return (ECPrivateKey)ECGeneratePrivate(keySpec); + } + + private static PublicKey ECGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + try { + if (keySpec instanceof X509EncodedKeySpec) { + X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec; + return new ECPublicKeyImpl(x509Spec.getEncoded()); + } else if (keySpec instanceof ECPublicKeySpec) { + ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec; + return new ECPublicKeyImpl( + ecSpec.getW(), + ecSpec.getParams() + ); + } else { + throw new InvalidKeySpecException("Only ECPublicKeySpec " + + "and X509EncodedKeySpec supported for EC public keys"); + } + } catch (InvalidKeySpecException e) { + throw e; + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException(e); + } + } + + private static PrivateKey ECGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + try { + if (keySpec instanceof PKCS8EncodedKeySpec) { + PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec; + return new ECPrivateKeyImpl(pkcsSpec.getEncoded()); + } else if (keySpec instanceof ECPrivateKeySpec) { + ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec; + return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams()); + } else { + throw new InvalidKeySpecException("Only ECPrivateKeySpec " + + "and PKCS8EncodedKeySpec supported for EC private keys"); + } + } catch (InvalidKeySpecException e) { + throw e; + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException(e); + } + } + + private P11ECUtil() {} + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11Key.java b/src/main/java/com/sunyard/security/pkcs11/P11Key.java new file mode 100644 index 0000000..2bd0ad1 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11Key.java @@ -0,0 +1,1408 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.*; +import java.lang.ref.*; +import java.math.BigInteger; +import java.util.*; +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; + +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +import sun.security.rsa.RSAUtil.KeyType; +import sun.security.rsa.RSAPublicKeyImpl; +import sun.security.rsa.RSAPrivateCrtKeyImpl; + +import sun.security.internal.interfaces.TlsMasterSecret; + +import com.sunyard.security.pkcs11.wrapper.*; + +import static com.sunyard.security.pkcs11.TemplateManager.O_GENERATE; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +import sun.security.util.DerValue; +import sun.security.util.Length; + +import sun.security.jca.JCAUtil; + +/** + * Key implementation classes. + * + * In PKCS#11, the components of private and secret keys may or may not + * be accessible. If they are, we use the algorithm specific key classes + * (e.g. DSAPrivateKey) for compatibility with existing applications. + * If the components are not accessible, we use a generic class that + * only implements PrivateKey (or SecretKey). Whether the components of a + * key are extractable is automatically determined when the key object is + * created. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +abstract class P11Key implements Key, Length { + + private static final long serialVersionUID = -2575874101938349339L; + + private final static String PUBLIC = "public"; + private final static String PRIVATE = "private"; + private final static String SECRET = "secret"; + + // type of key, one of (PUBLIC, PRIVATE, SECRET) + final String type; + + // token instance + final Token token; + + // algorithm name, returned by getAlgorithm(), etc. + final String algorithm; + + // effective key length of the key, e.g. 56 for a DES key + final int keyLength; + + // flags indicating whether the key is a token object, sensitive, extractable + final boolean tokenObject, sensitive, extractable; + + private final NativeKeyHolder keyIDHolder; + + private static final boolean DISABLE_NATIVE_KEYS_EXTRACTION; + + /** + * {@systemProperty sun.security.pkcs11.disableKeyExtraction} property + * indicating whether or not cryptographic keys within tokens are + * extracted to a Java byte array for memory management purposes. + * + * Key extraction affects NSS PKCS11 library only. + * + */ + static { + PrivilegedAction getKeyExtractionProp = + () -> System.getProperty( + "sun.security.pkcs11.disableKeyExtraction", "false"); + String disableKeyExtraction = + AccessController.doPrivileged(getKeyExtractionProp); + DISABLE_NATIVE_KEYS_EXTRACTION = + "true".equalsIgnoreCase(disableKeyExtraction); + } + + P11Key(String type, Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + this.type = type; + this.token = session.token; + this.algorithm = algorithm; + this.keyLength = keyLength; + boolean tokenObject = false; + boolean sensitive = false; + boolean extractable = true; + int n = (attributes == null) ? 0 : attributes.length; + for (int i = 0; i < n; i++) { + CK_ATTRIBUTE attr = attributes[i]; + if (attr.type == CKA_TOKEN) { + tokenObject = attr.getBoolean(); + } else if (attr.type == CKA_SENSITIVE) { + sensitive = attr.getBoolean(); + } else if (attr.type == CKA_EXTRACTABLE) { + extractable = attr.getBoolean(); + } + } + this.tokenObject = tokenObject; + this.sensitive = sensitive; + this.extractable = extractable; + char[] tokenLabel = this.token.tokenInfo.label; + boolean isNSS = (tokenLabel[0] == 'N' && tokenLabel[1] == 'S' + && tokenLabel[2] == 'S'); + boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS && + extractable && !tokenObject); + this.keyIDHolder = new NativeKeyHolder(this, keyID, session, extractKeyInfo, + tokenObject); + } + + public long getKeyID() { + return keyIDHolder.getKeyID(); + } + + public void releaseKeyID() { + keyIDHolder.releaseKeyID(); + } + + // see JCA spec + public final String getAlgorithm() { + token.ensureValid(); + return algorithm; + } + + // see JCA spec + public final byte[] getEncoded() { + byte[] b = getEncodedInternal(); + return (b == null) ? null : b.clone(); + } + + abstract byte[] getEncodedInternal(); + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + // equals() should never throw exceptions + if (token.isValid() == false) { + return false; + } + if (obj instanceof Key == false) { + return false; + } + String thisFormat = getFormat(); + if (thisFormat == null) { + // no encoding, key only equal to itself + // XXX getEncoded() for unextractable keys will change that + return false; + } + Key other = (Key)obj; + if (thisFormat.equals(other.getFormat()) == false) { + return false; + } + byte[] thisEnc = this.getEncodedInternal(); + byte[] otherEnc; + if (obj instanceof P11Key) { + otherEnc = ((P11Key)other).getEncodedInternal(); + } else { + otherEnc = other.getEncoded(); + } + return MessageDigest.isEqual(thisEnc, otherEnc); + } + + public int hashCode() { + // hashCode() should never throw exceptions + if (token.isValid() == false) { + return 0; + } + byte[] b1 = getEncodedInternal(); + if (b1 == null) { + return 0; + } + int r = b1.length; + for (int i = 0; i < b1.length; i++) { + r += (b1[i] & 0xff) * 37; + } + return r; + } + + protected Object writeReplace() throws ObjectStreamException { + KeyRep.Type type; + String format = getFormat(); + if (isPrivate() && "PKCS#8".equals(format)) { + type = KeyRep.Type.PRIVATE; + } else if (isPublic() && "X.509".equals(format)) { + type = KeyRep.Type.PUBLIC; + } else if (isSecret() && "RAW".equals(format)) { + type = KeyRep.Type.SECRET; + } else { + // XXX short term serialization for unextractable keys + throw new NotSerializableException + ("Cannot serialize sensitive and unextractable keys"); + } + return new KeyRep(type, getAlgorithm(), format, getEncoded()); + } + + public String toString() { + token.ensureValid(); + String s1 = token.provider.getName() + " " + algorithm + " " + type + + " key, " + keyLength + " bits"; + s1 += (tokenObject ? "token" : "session") + " object"; + if (isPublic()) { + s1 += ")"; + } else { + s1 += ", " + (sensitive ? "" : "not ") + "sensitive"; + s1 += ", " + (extractable ? "" : "un") + "extractable)"; + } + return s1; + } + + /** + * Return bit length of the key. + */ + @Override + public int length() { + return keyLength; + } + + boolean isPublic() { + return type == PUBLIC; + } + + boolean isPrivate() { + return type == PRIVATE; + } + + boolean isSecret() { + return type == SECRET; + } + + void fetchAttributes(CK_ATTRIBUTE[] attributes) { + Session tempSession = null; + long keyID = this.getKeyID(); + try { + tempSession = token.getOpSession(); + token.p11.C_GetAttributeValue(tempSession.id(), keyID, + attributes); + } catch (PKCS11Exception e) { + throw new ProviderException(e); + } finally { + this.releaseKeyID(); + token.releaseSession(tempSession); + } + } + + private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0]; + + private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID, + CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) { + if (knownAttributes == null) { + knownAttributes = A0; + } + for (int i = 0; i < desiredAttributes.length; i++) { + // For each desired attribute, check to see if we have the value + // available already. If everything is here, we save a native call. + CK_ATTRIBUTE attr = desiredAttributes[i]; + for (CK_ATTRIBUTE known : knownAttributes) { + if ((attr.type == known.type) && (known.pValue != null)) { + attr.pValue = known.pValue; + break; // break inner for loop + } + } + if (attr.pValue == null) { + // nothing found, need to call C_GetAttributeValue() + for (int j = 0; j < i; j++) { + // clear values copied from knownAttributes + desiredAttributes[j].pValue = null; + } + try { + session.token.p11.C_GetAttributeValue + (session.id(), keyID, desiredAttributes); + } catch (PKCS11Exception e) { + throw new ProviderException(e); + } + break; // break loop, goto return + } + } + return desiredAttributes; + } + + static SecretKey secretKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_TOKEN), + new CK_ATTRIBUTE(CKA_SENSITIVE), + new CK_ATTRIBUTE(CKA_EXTRACTABLE), + }); + return new P11SecretKey(session, keyID, algorithm, keyLength, + attributes); + } + + static SecretKey masterSecretKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) { + attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_TOKEN), + new CK_ATTRIBUTE(CKA_SENSITIVE), + new CK_ATTRIBUTE(CKA_EXTRACTABLE), + }); + return new P11TlsMasterSecretKey( + session, keyID, algorithm, keyLength, attributes, major, + minor); + } + + // we assume that all components of public keys are always accessible + static PublicKey publicKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + switch (algorithm) { + case "RSA": + return new P11RSAPublicKey(session, keyID, algorithm, + keyLength, attributes); + case "DSA": + return new P11DSAPublicKey(session, keyID, algorithm, + keyLength, attributes); + case "DH": + return new P11DHPublicKey(session, keyID, algorithm, + keyLength, attributes); + case "EC": + return new P11ECPublicKey(session, keyID, algorithm, + keyLength, attributes); + default: + throw new ProviderException + ("Unknown public key algorithm " + algorithm); + } + } + + static PrivateKey privateKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_TOKEN), + new CK_ATTRIBUTE(CKA_SENSITIVE), + new CK_ATTRIBUTE(CKA_EXTRACTABLE), + }); + if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) { + return new P11PrivateKey + (session, keyID, algorithm, keyLength, attributes); + } else { + switch (algorithm) { + case "RSA": + // XXX better test for RSA CRT keys (single getAttributes() call) + // we need to determine whether this is a CRT key + // see if we can obtain the public exponent + // this should also be readable for sensitive/extractable keys + CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), + }; + boolean crtKey; + try { + session.token.p11.C_GetAttributeValue + (session.id(), keyID, attrs2); + crtKey = (attrs2[0].pValue instanceof byte[]); + } catch (PKCS11Exception e) { + // ignore, assume not available + crtKey = false; + } + if (crtKey) { + return new P11RSAPrivateKey(session, keyID, algorithm, + keyLength, attributes); + } else { + return new P11RSAPrivateNonCRTKey(session, keyID, + algorithm, keyLength, attributes); + } + case "DSA": + return new P11DSAPrivateKey(session, keyID, algorithm, + keyLength, attributes); + case "DH": + return new P11DHPrivateKey(session, keyID, algorithm, + keyLength, attributes); + case "EC": + return new P11ECPrivateKey(session, keyID, algorithm, + keyLength, attributes); + default: + throw new ProviderException + ("Unknown private key algorithm " + algorithm); + } + } + } + + // class for sensitive and unextractable private keys + private static final class P11PrivateKey extends P11Key + implements PrivateKey { + private static final long serialVersionUID = -2138581185214187615L; + + P11PrivateKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + } + // XXX temporary encoding for serialization purposes + public String getFormat() { + token.ensureValid(); + return null; + } + byte[] getEncodedInternal() { + token.ensureValid(); + return null; + } + } + + private static class P11SecretKey extends P11Key implements SecretKey { + private static final long serialVersionUID = -7828241727014329084L; + private volatile byte[] encoded; + P11SecretKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(SECRET, session, keyID, algorithm, keyLength, attributes); + } + public String getFormat() { + token.ensureValid(); + if (sensitive || (extractable == false)) { + return null; + } else { + return "RAW"; + } + } + byte[] getEncodedInternal() { + token.ensureValid(); + if (getFormat() == null) { + return null; + } + byte[] b = encoded; + if (b == null) { + synchronized (this) { + b = encoded; + if (b == null) { + Session tempSession = null; + long keyID = this.getKeyID(); + try { + tempSession = token.getOpSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + }; + token.p11.C_GetAttributeValue + (tempSession.id(), keyID, attributes); + b = attributes[0].getByteArray(); + } catch (PKCS11Exception e) { + throw new ProviderException(e); + } finally { + this.releaseKeyID(); + token.releaseSession(tempSession); + } + encoded = b; + } + } + } + return b; + } + } + + private static class P11TlsMasterSecretKey extends P11SecretKey + implements TlsMasterSecret { + private static final long serialVersionUID = -1318560923770573441L; + + private final int majorVersion, minorVersion; + P11TlsMasterSecretKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) { + super(session, keyID, algorithm, keyLength, attributes); + this.majorVersion = major; + this.minorVersion = minor; + } + public int getMajorVersion() { + return majorVersion; + } + + public int getMinorVersion() { + return minorVersion; + } + } + + // RSA CRT private key + private static final class P11RSAPrivateKey extends P11Key + implements RSAPrivateCrtKey { + private static final long serialVersionUID = 9215872438913515220L; + + private BigInteger n, e, d, p, q, pe, qe, coeff; + private byte[] encoded; + P11RSAPrivateKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (n != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_MODULUS), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), + new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT), + new CK_ATTRIBUTE(CKA_PRIME_1), + new CK_ATTRIBUTE(CKA_PRIME_2), + new CK_ATTRIBUTE(CKA_EXPONENT_1), + new CK_ATTRIBUTE(CKA_EXPONENT_2), + new CK_ATTRIBUTE(CKA_COEFFICIENT), + }; + fetchAttributes(attributes); + n = attributes[0].getBigInteger(); + e = attributes[1].getBigInteger(); + d = attributes[2].getBigInteger(); + p = attributes[3].getBigInteger(); + q = attributes[4].getBigInteger(); + pe = attributes[5].getBigInteger(); + qe = attributes[6].getBigInteger(); + coeff = attributes[7].getBigInteger(); + } + public String getFormat() { + token.ensureValid(); + return "PKCS#8"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + Key newKey = RSAPrivateCrtKeyImpl.newKey + (KeyType.RSA, null, n, e, d, p, q, pe, qe, coeff); + encoded = newKey.getEncoded(); + } catch (GeneralSecurityException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getModulus() { + fetchValues(); + return n; + } + public BigInteger getPublicExponent() { + fetchValues(); + return e; + } + public BigInteger getPrivateExponent() { + fetchValues(); + return d; + } + public BigInteger getPrimeP() { + fetchValues(); + return p; + } + public BigInteger getPrimeQ() { + fetchValues(); + return q; + } + public BigInteger getPrimeExponentP() { + fetchValues(); + return pe; + } + public BigInteger getPrimeExponentQ() { + fetchValues(); + return qe; + } + public BigInteger getCrtCoefficient() { + fetchValues(); + return coeff; + } + } + + // RSA non-CRT private key + private static final class P11RSAPrivateNonCRTKey extends P11Key + implements RSAPrivateKey { + private static final long serialVersionUID = 1137764983777411481L; + + private BigInteger n, d; + private byte[] encoded; + P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (n != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_MODULUS), + new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT), + }; + fetchAttributes(attributes); + n = attributes[0].getBigInteger(); + d = attributes[1].getBigInteger(); + } + public String getFormat() { + token.ensureValid(); + return "PKCS#8"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + // XXX make constructor in SunRsaSign provider public + // and call it directly + KeyFactory factory = KeyFactory.getInstance + ("RSA", P11Util.getSunRsaSignProvider()); + Key newKey = factory.translateKey(this); + encoded = newKey.getEncoded(); + } catch (GeneralSecurityException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getModulus() { + fetchValues(); + return n; + } + public BigInteger getPrivateExponent() { + fetchValues(); + return d; + } + } + + private static final class P11RSAPublicKey extends P11Key + implements RSAPublicKey { + private static final long serialVersionUID = -826726289023854455L; + private BigInteger n, e; + private byte[] encoded; + P11RSAPublicKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (n != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_MODULUS), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), + }; + fetchAttributes(attributes); + n = attributes[0].getBigInteger(); + e = attributes[1].getBigInteger(); + } + public String getFormat() { + token.ensureValid(); + return "X.509"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + encoded = RSAPublicKeyImpl.newKey + (KeyType.RSA, null, n, e).getEncoded(); + } catch (InvalidKeyException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getModulus() { + fetchValues(); + return n; + } + public BigInteger getPublicExponent() { + fetchValues(); + return e; + } + public String toString() { + fetchValues(); + return super.toString() + "\n modulus: " + n + + "\n public exponent: " + e; + } + } + + private static final class P11DSAPublicKey extends P11Key + implements DSAPublicKey { + private static final long serialVersionUID = 5989753793316396637L; + + private BigInteger y; + private DSAParams params; + private byte[] encoded; + P11DSAPublicKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (y != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_SUBPRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + fetchAttributes(attributes); + y = attributes[0].getBigInteger(); + params = new DSAParameterSpec( + attributes[1].getBigInteger(), + attributes[2].getBigInteger(), + attributes[3].getBigInteger() + ); + } + public String getFormat() { + token.ensureValid(); + return "X.509"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + Key key = new sun.security.provider.DSAPublicKey + (y, params.getP(), params.getQ(), params.getG()); + encoded = key.getEncoded(); + } catch (InvalidKeyException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getY() { + fetchValues(); + return y; + } + public DSAParams getParams() { + fetchValues(); + return params; + } + public String toString() { + fetchValues(); + return super.toString() + "\n y: " + y + "\n p: " + params.getP() + + "\n q: " + params.getQ() + "\n g: " + params.getG(); + } + } + + private static final class P11DSAPrivateKey extends P11Key + implements DSAPrivateKey { + private static final long serialVersionUID = 3119629997181999389L; + + private BigInteger x; + private DSAParams params; + private byte[] encoded; + P11DSAPrivateKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (x != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_SUBPRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + fetchAttributes(attributes); + x = attributes[0].getBigInteger(); + params = new DSAParameterSpec( + attributes[1].getBigInteger(), + attributes[2].getBigInteger(), + attributes[3].getBigInteger() + ); + } + public String getFormat() { + token.ensureValid(); + return "PKCS#8"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + Key key = new sun.security.provider.DSAPrivateKey + (x, params.getP(), params.getQ(), params.getG()); + encoded = key.getEncoded(); + } catch (InvalidKeyException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getX() { + fetchValues(); + return x; + } + public DSAParams getParams() { + fetchValues(); + return params; + } + } + + private static final class P11DHPrivateKey extends P11Key + implements DHPrivateKey { + private static final long serialVersionUID = -1698576167364928838L; + + private BigInteger x; + private DHParameterSpec params; + private byte[] encoded; + P11DHPrivateKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (x != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + fetchAttributes(attributes); + x = attributes[0].getBigInteger(); + params = new DHParameterSpec( + attributes[1].getBigInteger(), + attributes[2].getBigInteger() + ); + } + public String getFormat() { + token.ensureValid(); + return "PKCS#8"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + DHPrivateKeySpec spec = new DHPrivateKeySpec + (x, params.getP(), params.getG()); + KeyFactory kf = KeyFactory.getInstance + ("DH", P11Util.getSunJceProvider()); + Key key = kf.generatePrivate(spec); + encoded = key.getEncoded(); + } catch (GeneralSecurityException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getX() { + fetchValues(); + return x; + } + public DHParameterSpec getParams() { + fetchValues(); + return params; + } + public int hashCode() { + if (token.isValid() == false) { + return 0; + } + fetchValues(); + return Objects.hash(x, params.getP(), params.getG()); + } + public boolean equals(Object obj) { + if (this == obj) return true; + // equals() should never throw exceptions + if (token.isValid() == false) { + return false; + } + if (!(obj instanceof DHPrivateKey)) { + return false; + } + fetchValues(); + DHPrivateKey other = (DHPrivateKey) obj; + DHParameterSpec otherParams = other.getParams(); + return ((this.x.compareTo(other.getX()) == 0) && + (this.params.getP().compareTo(otherParams.getP()) == 0) && + (this.params.getG().compareTo(otherParams.getG()) == 0)); + } + } + + private static final class P11DHPublicKey extends P11Key + implements DHPublicKey { + static final long serialVersionUID = -598383872153843657L; + + private BigInteger y; + private DHParameterSpec params; + private byte[] encoded; + P11DHPublicKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (y != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_PRIME), + new CK_ATTRIBUTE(CKA_BASE), + }; + fetchAttributes(attributes); + y = attributes[0].getBigInteger(); + params = new DHParameterSpec( + attributes[1].getBigInteger(), + attributes[2].getBigInteger() + ); + } + public String getFormat() { + token.ensureValid(); + return "X.509"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + DHPublicKeySpec spec = new DHPublicKeySpec + (y, params.getP(), params.getG()); + KeyFactory kf = KeyFactory.getInstance + ("DH", P11Util.getSunJceProvider()); + Key key = kf.generatePublic(spec); + encoded = key.getEncoded(); + } catch (GeneralSecurityException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getY() { + fetchValues(); + return y; + } + public DHParameterSpec getParams() { + fetchValues(); + return params; + } + public String toString() { + fetchValues(); + return super.toString() + "\n y: " + y + "\n p: " + params.getP() + + "\n g: " + params.getG(); + } + public int hashCode() { + if (token.isValid() == false) { + return 0; + } + fetchValues(); + return Objects.hash(y, params.getP(), params.getG()); + } + public boolean equals(Object obj) { + if (this == obj) return true; + // equals() should never throw exceptions + if (token.isValid() == false) { + return false; + } + if (!(obj instanceof DHPublicKey)) { + return false; + } + fetchValues(); + DHPublicKey other = (DHPublicKey) obj; + DHParameterSpec otherParams = other.getParams(); + return ((this.y.compareTo(other.getY()) == 0) && + (this.params.getP().compareTo(otherParams.getP()) == 0) && + (this.params.getG().compareTo(otherParams.getG()) == 0)); + } + } + + private static final class P11ECPrivateKey extends P11Key + implements ECPrivateKey { + private static final long serialVersionUID = -7786054399510515515L; + + private BigInteger s; + private ECParameterSpec params; + private byte[] encoded; + P11ECPrivateKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (s != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE), + new CK_ATTRIBUTE(CKA_EC_PARAMS, params), + }; + fetchAttributes(attributes); + s = attributes[0].getBigInteger(); + try { + params = P11ECKeyFactory.decodeParameters + (attributes[1].getByteArray()); + } catch (Exception e) { + throw new RuntimeException("Could not parse key values", e); + } + } + public String getFormat() { + token.ensureValid(); + return "PKCS#8"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + Key key = P11ECUtil.generateECPrivateKey(s, params); + encoded = key.getEncoded(); + } catch (InvalidKeySpecException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public BigInteger getS() { + fetchValues(); + return s; + } + public ECParameterSpec getParams() { + fetchValues(); + return params; + } + } + + private static final class P11ECPublicKey extends P11Key + implements ECPublicKey { + private static final long serialVersionUID = -6371481375154806089L; + + private ECPoint w; + private ECParameterSpec params; + private byte[] encoded; + P11ECPublicKey(Session session, long keyID, String algorithm, + int keyLength, CK_ATTRIBUTE[] attributes) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + } + private synchronized void fetchValues() { + token.ensureValid(); + if (w != null) { + return; + } + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_EC_POINT), + new CK_ATTRIBUTE(CKA_EC_PARAMS), + }; + fetchAttributes(attributes); + + try { + params = P11ECKeyFactory.decodeParameters + (attributes[1].getByteArray()); + byte[] ecKey = attributes[0].getByteArray(); + + // Check whether the X9.63 encoding of an EC point is wrapped + // in an ASN.1 OCTET STRING + if (!token.config.getUseEcX963Encoding()) { + DerValue wECPoint = new DerValue(ecKey); + + if (wECPoint.getTag() != DerValue.tag_OctetString) { + throw new IOException("Could not DER decode EC point." + + " Unexpected tag: " + wECPoint.getTag()); + } + w = P11ECKeyFactory.decodePoint + (wECPoint.getDataBytes(), params.getCurve()); + + } else { + w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve()); + } + + } catch (Exception e) { + throw new RuntimeException("Could not parse key values", e); + } + } + public String getFormat() { + token.ensureValid(); + return "X.509"; + } + synchronized byte[] getEncodedInternal() { + token.ensureValid(); + if (encoded == null) { + fetchValues(); + try { + return P11ECUtil.x509EncodeECPublicKey(w, params); + } catch (InvalidKeySpecException e) { + throw new ProviderException(e); + } + } + return encoded; + } + public ECPoint getW() { + fetchValues(); + return w; + } + public ECParameterSpec getParams() { + fetchValues(); + return params; + } + public String toString() { + fetchValues(); + return super.toString() + + "\n public x coord: " + w.getAffineX() + + "\n public y coord: " + w.getAffineY() + + "\n parameters: " + params; + } + } +} + +final class NativeKeyHolder { + + private static long nativeKeyWrapperKeyID = 0; + private static CK_MECHANISM nativeKeyWrapperMechanism = null; + private static long nativeKeyWrapperRefCount = 0; + private static Session nativeKeyWrapperSession = null; + + private final P11Key p11Key; + private final byte[] nativeKeyInfo; + private boolean wrapperKeyUsed; + + // destroyed and recreated when refCount toggles to 1 + private long keyID; + + // phantom reference notification clean up for session keys + private SessionKeyRef ref; + + private int refCount; + + private static void createNativeKeyWrapper(Token token) + throws PKCS11Exception { + assert(nativeKeyWrapperKeyID == 0); + assert(nativeKeyWrapperRefCount == 0); + assert(nativeKeyWrapperSession == null); + // Create a global wrapping/unwrapping key + CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes(O_GENERATE, + CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3)}); + Session s = null; + try { + s = token.getObjSession(); + nativeKeyWrapperKeyID = token.p11.C_GenerateKey( + s.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), + wrappingAttributes); + nativeKeyWrapperSession = s; + nativeKeyWrapperSession.addObject(); + byte[] iv = new byte[16]; + JCAUtil.getSecureRandom().nextBytes(iv); + nativeKeyWrapperMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, iv); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } + + private static void deleteNativeKeyWrapper() { + Token token = nativeKeyWrapperSession.token; + if (token.isValid()) { + Session s = null; + try { + s = token.getOpSession(); + token.p11.C_DestroyObject(s.id(), nativeKeyWrapperKeyID); + nativeKeyWrapperSession.removeObject(); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } + nativeKeyWrapperKeyID = 0; + nativeKeyWrapperMechanism = null; + nativeKeyWrapperSession = null; + } + + static void decWrapperKeyRef() { + synchronized(NativeKeyHolder.class) { + assert(nativeKeyWrapperKeyID != 0); + assert(nativeKeyWrapperRefCount > 0); + nativeKeyWrapperRefCount--; + if (nativeKeyWrapperRefCount == 0) { + deleteNativeKeyWrapper(); + } + } + } + + NativeKeyHolder(P11Key p11Key, long keyID, Session keySession, + boolean extractKeyInfo, boolean isTokenObject) { + this.p11Key = p11Key; + this.keyID = keyID; + this.refCount = -1; + byte[] ki = null; + if (isTokenObject) { + this.ref = null; + } else { + // Try extracting key info, if any error, disable it + Token token = p11Key.token; + if (extractKeyInfo) { + try { + if (p11Key.sensitive) { + // p11Key native key information has to be wrapped + synchronized(NativeKeyHolder.class) { + if (nativeKeyWrapperKeyID == 0) { + createNativeKeyWrapper(token); + } + // If a wrapper-key was successfully created or + // already exists, increment its reference + // counter to keep it alive while native key + // information is being held. + if (nativeKeyWrapperKeyID != 0) { + nativeKeyWrapperRefCount++; + wrapperKeyUsed = true; + } + } + } + Session opSession = null; + try { + opSession = token.getOpSession(); + ki = p11Key.token.p11.getNativeKeyInfo(opSession.id(), + keyID, nativeKeyWrapperKeyID, + nativeKeyWrapperMechanism); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(opSession); + } + } catch (PKCS11Exception e) { + // best effort + } + } + this.ref = new SessionKeyRef(p11Key, keyID, wrapperKeyUsed, + keySession); + } + this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki); + } + + long getKeyID() throws ProviderException { + if (this.nativeKeyInfo != null) { + synchronized(this.nativeKeyInfo) { + if (this.refCount == -1) { + this.refCount = 0; + } + int cnt = (this.refCount)++; + if (keyID == 0) { + if (cnt != 0) { + throw new RuntimeException( + "Error: null keyID with non-zero refCount " + cnt); + } + Token token = p11Key.token; + // Create keyID using nativeKeyInfo + Session session = null; + try { + session = token.getObjSession(); + this.keyID = token.p11.createNativeKey(session.id(), + nativeKeyInfo, nativeKeyWrapperKeyID, + nativeKeyWrapperMechanism); + this.ref.registerNativeKey(this.keyID, session); + } catch (PKCS11Exception e) { + this.refCount--; + throw new ProviderException("Error recreating native key", e); + } finally { + token.releaseSession(session); + } + } else { + if (cnt < 0) { + throw new RuntimeException("ERROR: negative refCount"); + } + } + } + } + return keyID; + } + + void releaseKeyID() { + if (this.nativeKeyInfo != null) { + synchronized(this.nativeKeyInfo) { + if (this.refCount == -1) { + throw new RuntimeException("Error: miss match getKeyID call"); + } + int cnt = --(this.refCount); + if (cnt == 0) { + // destroy + if (this.keyID == 0) { + throw new RuntimeException("ERROR: null keyID can't be destroyed"); + } + + // destroy + this.keyID = 0; + this.ref.removeNativeKey(); + } else { + if (cnt < 0) { + // should never happen as we start count at 1 and pair get/release calls + throw new RuntimeException("wrong refCount value: " + cnt); + } + } + } + } + } +} + +/* + * NOTE: Must use PhantomReference here and not WeakReference + * otherwise the key maybe cleared before other objects which + * still use these keys during finalization such as SSLSocket. + */ +final class SessionKeyRef extends PhantomReference { + private static ReferenceQueue refQueue = + new ReferenceQueue(); + private static Set refSet = + Collections.synchronizedSet(new HashSet()); + + static ReferenceQueue referenceQueue() { + return refQueue; + } + + private static void drainRefQueueBounded() { + while (true) { + SessionKeyRef next = (SessionKeyRef) refQueue.poll(); + if (next == null) break; + next.dispose(); + } + } + + // handle to the native key and the session it is generated under + private long keyID; + private Session session; + private boolean wrapperKeyUsed; + + SessionKeyRef(P11Key p11Key, long keyID, boolean wrapperKeyUsed, + Session session) { + super(p11Key, refQueue); + if (session == null) { + throw new ProviderException("key must be associated with a session"); + } + registerNativeKey(keyID, session); + this.wrapperKeyUsed = wrapperKeyUsed; + + refSet.add(this); + // TBD: run at some interval and not every time? + drainRefQueueBounded(); + } + + void registerNativeKey(long newKeyID, Session newSession) { + assert(newKeyID != 0); + assert(newSession != null); + updateNativeKey(newKeyID, newSession); + } + + void removeNativeKey() { + assert(session != null); + updateNativeKey(0, null); + } + + private void updateNativeKey(long newKeyID, Session newSession) { + if (newKeyID == 0) { + assert(newSession == null); + Token token = session.token; + // If the token is still valid, try to remove the key object + if (token.isValid()) { + Session s = null; + try { + s = token.getOpSession(); + token.p11.C_DestroyObject(s.id(), this.keyID); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } + session.removeObject(); + } else { + newSession.addObject(); + } + keyID = newKeyID; + session = newSession; + } + + // Called when the GC disposes a p11Key + void dispose() { + if (wrapperKeyUsed) { + // Wrapper-key no longer needed for + // p11Key native key information + NativeKeyHolder.decWrapperKeyRef(); + } + if (keyID != 0) { + removeNativeKey(); + } + refSet.remove(this); + this.clear(); + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11KeyAgreement.java b/src/main/java/com/sunyard/security/pkcs11/P11KeyAgreement.java new file mode 100644 index 0000000..5217bfe --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11KeyAgreement.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; + +import java.security.*; +import java.security.spec.*; + +import javax.crypto.*; +import javax.crypto.interfaces.*; +import javax.crypto.spec.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; +import sun.security.util.KeyUtil; + +/** + * KeyAgreement implementation class. This class currently supports + * DH. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11KeyAgreement extends KeyAgreementSpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private final long mechanism; + + // private key, if initialized + private P11Key privateKey; + + // other sides public value ("y"), if doPhase() already called + private BigInteger publicValue; + + // length of the secret to be derived + private int secretLen; + + // KeyAgreement from SunJCE as fallback for > 2 party agreement + private KeyAgreement multiPartyAgreement; + + private static class AllowKDF { + + private static final boolean VALUE = getValue(); + + private static boolean getValue() { + return AccessController.doPrivileged( + (PrivilegedAction) + () -> Boolean.getBoolean("jdk.crypto.KeyAgreement.legacyKDF")); + } + } + + P11KeyAgreement(Token token, String algorithm, long mechanism) { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + } + + // see JCE spec + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException { + if (key instanceof PrivateKey == false) { + throw new InvalidKeyException + ("Key must be instance of PrivateKey"); + } + privateKey = P11KeyFactory.convertKey(token, key, algorithm); + publicValue = null; + multiPartyAgreement = null; + } + + // see JCE spec + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException + ("Parameters not supported"); + } + engineInit(key, random); + } + + // see JCE spec + protected Key engineDoPhase(Key key, boolean lastPhase) + throws InvalidKeyException, IllegalStateException { + if (privateKey == null) { + throw new IllegalStateException("Not initialized"); + } + if (publicValue != null) { + throw new IllegalStateException("Phase already executed"); + } + // PKCS#11 only allows key agreement between 2 parties + // JCE allows >= 2 parties. To support that case (for compatibility + // and to pass JCK), fall back to SunJCE in this case. + // NOTE that we initialize using the P11Key, which will fail if it + // is sensitive/unextractable. However, this is not an issue in the + // compatibility configuration, which is all we are targeting here. + if ((multiPartyAgreement != null) || (lastPhase == false)) { + if (multiPartyAgreement == null) { + try { + multiPartyAgreement = KeyAgreement.getInstance + ("DH", P11Util.getSunJceProvider()); + multiPartyAgreement.init(privateKey); + } catch (NoSuchAlgorithmException e) { + throw new InvalidKeyException + ("Could not initialize multi party agreement", e); + } + } + return multiPartyAgreement.doPhase(key, lastPhase); + } + if ((key instanceof PublicKey == false) + || (key.getAlgorithm().equals(algorithm) == false)) { + throw new InvalidKeyException + ("Key must be a PublicKey with algorithm DH"); + } + BigInteger p, g, y; + if (key instanceof DHPublicKey) { + DHPublicKey dhKey = (DHPublicKey)key; + + // validate the Diffie-Hellman public key + KeyUtil.validate(dhKey); + + y = dhKey.getY(); + DHParameterSpec params = dhKey.getParams(); + p = params.getP(); + g = params.getG(); + } else { + // normally, DH PublicKeys will always implement DHPublicKey + // just in case not, attempt conversion + P11DHKeyFactory kf = new P11DHKeyFactory(token, "DH"); + try { + DHPublicKeySpec spec = kf.engineGetKeySpec( + key, DHPublicKeySpec.class); + + // validate the Diffie-Hellman public key + KeyUtil.validate(spec); + + y = spec.getY(); + p = spec.getP(); + g = spec.getG(); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException("Could not obtain key values", e); + } + } + // if parameters of private key are accessible, verify that + // they match parameters of public key + // XXX p and g should always be readable, even if the key is sensitive + if (privateKey instanceof DHPrivateKey) { + DHPrivateKey dhKey = (DHPrivateKey)privateKey; + DHParameterSpec params = dhKey.getParams(); + if ((p.equals(params.getP()) == false) + || (g.equals(params.getG()) == false)) { + throw new InvalidKeyException + ("PublicKey DH parameters must match PrivateKey DH parameters"); + } + } + publicValue = y; + // length of the secret is length of key + secretLen = (p.bitLength() + 7) >> 3; + return null; + } + + // see JCE spec + protected byte[] engineGenerateSecret() throws IllegalStateException { + if (multiPartyAgreement != null) { + byte[] val = multiPartyAgreement.generateSecret(); + multiPartyAgreement = null; + return val; + } + if ((privateKey == null) || (publicValue == null)) { + throw new IllegalStateException("Not initialized correctly"); + } + Session session = null; + long privKeyID = privateKey.getKeyID(); + try { + session = token.getOpSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET), + }; + attributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); + long keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, publicValue), privKeyID, + attributes); + + attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE) + }; + token.p11.C_GetAttributeValue(session.id(), keyID, attributes); + byte[] secret = attributes[0].getByteArray(); + token.p11.C_DestroyObject(session.id(), keyID); + // Some vendors, e.g. NSS, trim off the leading 0x00 byte(s) from + // the generated secret. Thus, we need to check the secret length + // and trim/pad it so the returned value has the same length as + // the modulus size + if (secret.length == secretLen) { + return secret; + } else { + if (secret.length > secretLen) { + // Shouldn't happen; but check just in case + throw new ProviderException("generated secret is out-of-range"); + } + byte[] newSecret = new byte[secretLen]; + System.arraycopy(secret, 0, newSecret, secretLen - secret.length, + secret.length); + return newSecret; + } + } catch (PKCS11Exception e) { + throw new ProviderException("Could not derive key", e); + } finally { + privateKey.releaseKeyID(); + publicValue = null; + token.releaseSession(session); + } + } + + // see JCE spec + protected int engineGenerateSecret(byte[] sharedSecret, int + offset) throws IllegalStateException, ShortBufferException { + if (multiPartyAgreement != null) { + int n = multiPartyAgreement.generateSecret(sharedSecret, offset); + multiPartyAgreement = null; + return n; + } + if (offset + secretLen > sharedSecret.length) { + throw new ShortBufferException("Need " + secretLen + + " bytes, only " + (sharedSecret.length - offset) + " available"); + } + byte[] secret = engineGenerateSecret(); + System.arraycopy(secret, 0, sharedSecret, offset, secret.length); + return secret.length; + } + + // see JCE spec + protected SecretKey engineGenerateSecret(String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, + InvalidKeyException { + if (multiPartyAgreement != null) { + SecretKey key = multiPartyAgreement.generateSecret(algorithm); + multiPartyAgreement = null; + return key; + } + if (algorithm == null) { + throw new NoSuchAlgorithmException("Algorithm must not be null"); + } + + if (algorithm.equals("TlsPremasterSecret")) { + // For now, only perform native derivation for TlsPremasterSecret + // as that is required for FIPS compliance. + // For other algorithms, there are unresolved issues regarding + // how this should work in JCE plus a Solaris truncation bug. + // (bug not yet filed). + return nativeGenerateSecret(algorithm); + } + + if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") && + !AllowKDF.VALUE) { + + throw new NoSuchAlgorithmException("Unsupported secret key " + + "algorithm: " + algorithm); + } + + byte[] secret = engineGenerateSecret(); + // Maintain compatibility for SunJCE: + // verify secret length is sensible for algorithm / truncate + // return generated key itself if possible + int keyLen; + if (algorithm.equalsIgnoreCase("DES")) { + keyLen = 8; + } else if (algorithm.equalsIgnoreCase("DESede")) { + keyLen = 24; + } else if (algorithm.equalsIgnoreCase("Blowfish")) { + keyLen = Math.min(56, secret.length); + } else if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) { + keyLen = secret.length; + } else { + throw new NoSuchAlgorithmException + ("Unknown algorithm " + algorithm); + } + if (secret.length < keyLen) { + throw new InvalidKeyException("Secret too short"); + } + if (algorithm.equalsIgnoreCase("DES") || + algorithm.equalsIgnoreCase("DESede")) { + for (int i = 0; i < keyLen; i+=8) { + P11SecretKeyFactory.fixDESParity(secret, i); + } + } + return new SecretKeySpec(secret, 0, keyLen, algorithm); + } + + private SecretKey nativeGenerateSecret(String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, + InvalidKeyException { + if ((privateKey == null) || (publicValue == null)) { + throw new IllegalStateException("Not initialized correctly"); + } + long keyType = CKK_GENERIC_SECRET; + Session session = null; + long privKeyID = privateKey.getKeyID(); + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + attributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); + long keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, publicValue), privKeyID, + attributes); + CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE_LEN), + }; + token.p11.C_GetAttributeValue(session.id(), keyID, lenAttributes); + int keyLen = (int)lenAttributes[0].getLong(); + SecretKey key = P11Key.secretKey + (session, keyID, algorithm, keyLen << 3, attributes); + if ("RAW".equals(key.getFormat())) { + // Workaround for Solaris bug 6318543. + // Strip leading zeroes ourselves if possible (key not sensitive). + // This should be removed once the Solaris fix is available + // as here we always retrieve the CKA_VALUE even for tokens + // that do not have that bug. + byte[] keyBytes = key.getEncoded(); + byte[] newBytes = KeyUtil.trimZeroes(keyBytes); + if (keyBytes != newBytes) { + key = new SecretKeySpec(newBytes, algorithm); + } + } + return key; + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not derive key", e); + } finally { + privateKey.releaseKeyID(); + publicValue = null; + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11KeyFactory.java b/src/main/java/com/sunyard/security/pkcs11/P11KeyFactory.java new file mode 100644 index 0000000..5862999 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11KeyFactory.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.spec.*; + +import com.sunyard.security.pkcs11.wrapper.PKCS11Exception; + +/** + * KeyFactory base class. Provides common infrastructure for the RSA, DSA, + * and DH implementations. + * + * The subclasses support conversion between keys and keyspecs + * using X.509, PKCS#8, and their individual algorithm specific formats, + * assuming keys are extractable. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +abstract class P11KeyFactory extends KeyFactorySpi { + + // token instance + final Token token; + + // algorithm name, currently one of RSA, DSA, DH + final String algorithm; + + P11KeyFactory(Token token, String algorithm) { + super(); + this.token = token; + this.algorithm = algorithm; + } + + /** + * Convert an arbitrary key of algorithm into a P11Key of token. + * Used by P11Signature.init() and RSACipher.init(). + */ + static P11Key convertKey(Token token, Key key, String algorithm) + throws InvalidKeyException { + return (P11Key)token.getKeyFactory(algorithm).engineTranslateKey(key); + } + + // see JCA spec + protected final T engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if ((key == null) || (keySpec == null)) { + throw new InvalidKeySpecException + ("key and keySpec must not be null"); + } + // delegate to our Java based providers for PKCS#8 and X.509 + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class) + || keySpec.isAssignableFrom(X509EncodedKeySpec.class)) { + try { + return implGetSoftwareFactory().getKeySpec(key, keySpec); + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException("Could not encode key", e); + } + } + // first translate into a key of this token, if it is not already + P11Key p11Key; + try { + p11Key = (P11Key)engineTranslateKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException("Could not convert key", e); + } + Session[] session = new Session[1]; + try { + if (p11Key.isPublic()) { + return implGetPublicKeySpec(p11Key, keySpec, session); + } else { + return implGetPrivateKeySpec(p11Key, keySpec, session); + } + } catch (PKCS11Exception e) { + throw new InvalidKeySpecException("Could not generate KeySpec", e); + } finally { + session[0] = token.releaseSession(session[0]); + } + } + + // see JCA spec + protected final Key engineTranslateKey(Key key) throws InvalidKeyException { + token.ensureValid(); + if (key == null) { + throw new InvalidKeyException("Key must not be null"); + } + if (key.getAlgorithm().equals(this.algorithm) == false) { + throw new InvalidKeyException + ("Key algorithm must be " + algorithm); + } + if (key instanceof P11Key) { + P11Key p11Key = (P11Key)key; + if (p11Key.token == token) { + // already a key of this token, no need to translate + return key; + } + } + P11Key p11Key = token.privateCache.get(key); + if (p11Key != null) { + return p11Key; + } + if (key instanceof PublicKey) { + PublicKey publicKey = implTranslatePublicKey((PublicKey)key); + token.privateCache.put(key, (P11Key)publicKey); + return publicKey; + } else if (key instanceof PrivateKey) { + PrivateKey privateKey = implTranslatePrivateKey((PrivateKey)key); + token.privateCache.put(key, (P11Key)privateKey); + return privateKey; + } else { + throw new InvalidKeyException + ("Key must be instance of PublicKey or PrivateKey"); + } + } + + abstract T implGetPublicKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException; + + abstract T implGetPrivateKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException; + + abstract PublicKey implTranslatePublicKey(PublicKey key) + throws InvalidKeyException; + + abstract PrivateKey implTranslatePrivateKey(PrivateKey key) + throws InvalidKeyException; + + abstract KeyFactory implGetSoftwareFactory() throws GeneralSecurityException; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11KeyGenerator.java b/src/main/java/com/sunyard/security/pkcs11/P11KeyGenerator.java new file mode 100644 index 0000000..9b81e6c --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11KeyGenerator.java @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * KeyGenerator implementation class. This class currently supports + * DES, DESede, AES, ARCFOUR, and Blowfish. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11KeyGenerator extends KeyGeneratorSpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private long mechanism; + + // raw key size in bits, e.g. 64 for DES. Always valid. + private int keySize; + + // bits of entropy in the key, e.g. 56 for DES. Always valid. + private int significantKeySize; + + // keyType (CKK_*), needed for TemplateManager call only. + private long keyType; + + // for determining if both 112 and 168 bits of DESede key lengths + // are supported. + private boolean supportBothKeySizes; + + /** + * Utility method for checking if the specified key size is valid + * and within the supported range. Return the significant key size + * upon successful validation. + * @param keyGenMech the PKCS#11 key generation mechanism. + * @param keySize the to-be-checked key size for this mechanism. + * @param token token which provides this mechanism. + * @return the significant key size (in bits) corresponding to the + * specified key size. + * @throws InvalidParameterException if the specified key size is invalid. + * @throws ProviderException if this mechanism isn't supported by SunPKCS11 + * or underlying native impl. + */ + static int checkKeySize(long keyGenMech, int keySize, Token token) + throws InvalidAlgorithmParameterException, ProviderException { + int sigKeySize; + switch ((int)keyGenMech) { + case (int)CKM_DES_KEY_GEN: + if ((keySize != 64) && (keySize != 56)) { + throw new InvalidAlgorithmParameterException + ("DES key length must be 56 bits"); + } + sigKeySize = 56; + break; + case (int)CKM_DES2_KEY_GEN: + case (int)CKM_DES3_KEY_GEN: + if ((keySize == 112) || (keySize == 128)) { + sigKeySize = 112; + } else if ((keySize == 168) || (keySize == 192)) { + sigKeySize = 168; + } else { + throw new InvalidAlgorithmParameterException + ("DESede key length must be 112, or 168 bits"); + } + break; + default: + // Handle all variable-key-length algorithms here + CK_MECHANISM_INFO info = null; + try { + info = token.getMechanismInfo(keyGenMech); + } catch (PKCS11Exception p11e) { + // Should never happen + throw new ProviderException + ("Cannot retrieve mechanism info", p11e); + } + if (info == null) { + // XXX Unable to retrieve the supported key length from + // the underlying native impl. Skip the checking for now. + return keySize; + } + // PKCS#11 defines these to be in number of bytes except for + // RC4 which is in bits. However, some PKCS#11 impls still use + // bytes for all mechs, e.g. NSS. We try to detect this + // inconsistency if the minKeySize seems unreasonably small. + int minKeySize = info.iMinKeySize; + int maxKeySize = info.iMaxKeySize; + if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) { + minKeySize = Math.multiplyExact(minKeySize, 8); + if (maxKeySize != Integer.MAX_VALUE) { + maxKeySize = Math.multiplyExact(maxKeySize, 8); + } + } + // Explicitly disallow keys shorter than 40-bits for security + if (minKeySize < 40) minKeySize = 40; + if (keySize < minKeySize || keySize > maxKeySize) { + throw new InvalidAlgorithmParameterException + ("Key length must be between " + minKeySize + + " and " + maxKeySize + " bits"); + } + if (keyGenMech == CKM_AES_KEY_GEN) { + if ((keySize != 128) && (keySize != 192) && + (keySize != 256)) { + throw new InvalidAlgorithmParameterException + ("AES key length must be " + minKeySize + + (maxKeySize >= 192? ", 192":"") + + (maxKeySize >= 256? ", or 256":"") + " bits"); + } + } + sigKeySize = keySize; + } + return sigKeySize; + } + + P11KeyGenerator(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + + if (this.mechanism == CKM_DES3_KEY_GEN) { + /* Given the current lookup order specified in SunPKCS11.java, + if CKM_DES2_KEY_GEN is used to construct this object, it + means that CKM_DES3_KEY_GEN is disabled or unsupported. + */ + supportBothKeySizes = + (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) && + (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null)); + } + setDefaultKeySize(); + } + + // set default keysize and also initialize keyType + private void setDefaultKeySize() { + switch ((int)mechanism) { + case (int)CKM_DES_KEY_GEN: + keySize = 64; + keyType = CKK_DES; + break; + case (int)CKM_DES2_KEY_GEN: + keySize = 128; + keyType = CKK_DES2; + break; + case (int)CKM_DES3_KEY_GEN: + keySize = 192; + keyType = CKK_DES3; + break; + case (int)CKM_AES_KEY_GEN: + keySize = 128; + keyType = CKK_AES; + break; + case (int)CKM_RC4_KEY_GEN: + keySize = 128; + keyType = CKK_RC4; + break; + case (int)CKM_BLOWFISH_KEY_GEN: + keySize = 128; + keyType = CKK_BLOWFISH; + break; + default: + throw new ProviderException("Unknown mechanism " + mechanism); + } + try { + significantKeySize = checkKeySize(mechanism, keySize, token); + } catch (InvalidAlgorithmParameterException iape) { + throw new ProviderException("Unsupported default key size", iape); + } + } + + // see JCE spec + protected void engineInit(SecureRandom random) { + token.ensureValid(); + setDefaultKeySize(); + } + + // see JCE spec + protected void engineInit(AlgorithmParameterSpec params, + SecureRandom random) throws InvalidAlgorithmParameterException { + throw new InvalidAlgorithmParameterException + ("AlgorithmParameterSpec not supported"); + } + + // see JCE spec + protected void engineInit(int keySize, SecureRandom random) { + token.ensureValid(); + int newSignificantKeySize; + try { + newSignificantKeySize = checkKeySize(mechanism, keySize, token); + } catch (InvalidAlgorithmParameterException iape) { + throw (InvalidParameterException) + (new InvalidParameterException().initCause(iape)); + } + if ((mechanism == CKM_DES2_KEY_GEN) || + (mechanism == CKM_DES3_KEY_GEN)) { + long newMechanism = (newSignificantKeySize == 112 ? + CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN); + if (mechanism != newMechanism) { + if (supportBothKeySizes) { + mechanism = newMechanism; + // Adjust keyType to reflect the mechanism change + keyType = (mechanism == CKM_DES2_KEY_GEN ? + CKK_DES2 : CKK_DES3); + } else { + throw new InvalidParameterException + ("Only " + significantKeySize + + "-bit DESede is supported"); + } + } + } + this.keySize = keySize; + this.significantKeySize = newSignificantKeySize; + } + + // see JCE spec + protected SecretKey engineGenerateKey() { + Session session = null; + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes; + switch ((int)keyType) { + case (int)CKK_DES: + case (int)CKK_DES2: + case (int)CKK_DES3: + // fixed length, do not specify CKA_VALUE_LEN + attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + }; + break; + default: + attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3), + }; + break; + } + attributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); + long keyID = token.p11.C_GenerateKey + (session.id(), new CK_MECHANISM(mechanism), attributes); + return P11Key.secretKey + (session, keyID, algorithm, significantKeySize, attributes); + } catch (PKCS11Exception e) { + throw new ProviderException("Could not generate key", e); + } finally { + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11KeyPairGenerator.java b/src/main/java/com/sunyard/security/pkcs11/P11KeyPairGenerator.java new file mode 100644 index 0000000..1780297 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11KeyPairGenerator.java @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; + +import java.security.*; +import java.security.spec.*; + +import javax.crypto.spec.DHParameterSpec; + +import sun.security.provider.ParameterCache; +import static sun.security.util.SecurityProviderConstants.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + + +import sun.security.rsa.RSAKeyFactory; + +/** + * KeyPairGenerator implementation class. This class currently supports + * RSA, DSA, DH, and EC. + * + * Note that for DSA and DH we rely on the Sun and SunJCE providers to + * obtain the parameters from. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11KeyPairGenerator extends KeyPairGeneratorSpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private final long mechanism; + + // selected or default key size, always valid + private int keySize; + + // parameters specified via init, if any + private AlgorithmParameterSpec params; + + // for RSA, selected or default value of public exponent, always valid + private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4; + + // the supported keysize range of the native PKCS11 library + // if mechanism info is unavailable, 0/Integer.MAX_VALUE is used + private final int minKeySize; + private final int maxKeySize; + + // SecureRandom instance, if specified in init + private SecureRandom random; + + P11KeyPairGenerator(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + int minKeyLen = 0; + int maxKeyLen = Integer.MAX_VALUE; + try { + CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism); + if (mechInfo != null) { + minKeyLen = mechInfo.iMinKeySize; + maxKeyLen = mechInfo.iMaxKeySize; + } + } catch (PKCS11Exception p11e) { + // Should never happen + throw new ProviderException + ("Unexpected error while getting mechanism info", p11e); + } + // set default key sizes and apply our own algorithm-specific limits + // override lower limit to disallow unsecure keys being generated + // override upper limit to deter DOS attack + if (algorithm.equals("EC")) { + keySize = DEF_EC_KEY_SIZE; + if (minKeyLen < 112) { + minKeyLen = 112; + } + if (maxKeyLen > 2048) { + maxKeyLen = 2048; + } + } else { + if (algorithm.equals("DSA")) { + keySize = DEF_DSA_KEY_SIZE; + } else if (algorithm.equals("RSA")) { + keySize = DEF_RSA_KEY_SIZE; + if (maxKeyLen > 64 * 1024) { + maxKeyLen = 64 * 1024; + } + } else { + keySize = DEF_DH_KEY_SIZE; + } + if (minKeyLen < 512) { + minKeyLen = 512; + } + } + + // auto-adjust default keysize in case it's out-of-range + if (keySize < minKeyLen) { + keySize = minKeyLen; + } + if (keySize > maxKeyLen) { + keySize = maxKeyLen; + } + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + this.minKeySize = minKeyLen; + this.maxKeySize = maxKeyLen; + initialize(keySize, null); + } + + // see JCA spec + @Override + public void initialize(int keySize, SecureRandom random) { + token.ensureValid(); + try { + checkKeySize(keySize, null); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidParameterException(e.getMessage()); + } + this.params = null; + if (algorithm.equals("EC")) { + params = P11ECKeyFactory.getECParameterSpec(keySize); + if (params == null) { + throw new InvalidParameterException( + "No EC parameters available for key size " + + keySize + " bits"); + } + } + this.keySize = keySize; + this.random = random; + } + + // see JCA spec + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + token.ensureValid(); + int tmpKeySize; + if (algorithm.equals("DH")) { + if (params instanceof DHParameterSpec == false) { + throw new InvalidAlgorithmParameterException + ("DHParameterSpec required for Diffie-Hellman"); + } + DHParameterSpec dhParams = (DHParameterSpec) params; + tmpKeySize = dhParams.getP().bitLength(); + checkKeySize(tmpKeySize, dhParams); + // XXX sanity check params + } else if (algorithm.equals("RSA")) { + if (params instanceof RSAKeyGenParameterSpec == false) { + throw new InvalidAlgorithmParameterException + ("RSAKeyGenParameterSpec required for RSA"); + } + RSAKeyGenParameterSpec rsaParams = + (RSAKeyGenParameterSpec) params; + tmpKeySize = rsaParams.getKeysize(); + checkKeySize(tmpKeySize, rsaParams); + // override the supplied params to null + params = null; + this.rsaPublicExponent = rsaParams.getPublicExponent(); + // XXX sanity check params + } else if (algorithm.equals("DSA")) { + if (params instanceof DSAParameterSpec == false) { + throw new InvalidAlgorithmParameterException + ("DSAParameterSpec required for DSA"); + } + DSAParameterSpec dsaParams = (DSAParameterSpec) params; + tmpKeySize = dsaParams.getP().bitLength(); + checkKeySize(tmpKeySize, dsaParams); + // XXX sanity check params + } else if (algorithm.equals("EC")) { + ECParameterSpec ecParams; + if (params instanceof ECParameterSpec) { + ecParams = P11ECKeyFactory.getECParameterSpec( + (ECParameterSpec)params); + if (ecParams == null) { + throw new InvalidAlgorithmParameterException + ("Unsupported curve: " + params); + } + } else if (params instanceof ECGenParameterSpec) { + String name = ((ECGenParameterSpec) params).getName(); + ecParams = P11ECKeyFactory.getECParameterSpec(name); + if (ecParams == null) { + throw new InvalidAlgorithmParameterException + ("Unknown curve name: " + name); + } + // override the supplied params with the derived one + params = ecParams; + } else { + throw new InvalidAlgorithmParameterException + ("ECParameterSpec or ECGenParameterSpec required for EC"); + } + tmpKeySize = ecParams.getCurve().getField().getFieldSize(); + checkKeySize(tmpKeySize, ecParams); + } else { + throw new ProviderException("Unknown algorithm: " + algorithm); + } + this.keySize = tmpKeySize; + this.params = params; + this.random = random; + } + + private void checkKeySize(int keySize, AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (keySize <= 0) { + throw new InvalidAlgorithmParameterException + ("key size must be positive, got " + keySize); + } + // check native range first + if (keySize < minKeySize) { + throw new InvalidAlgorithmParameterException(algorithm + + " key must be at least " + minKeySize + " bits. " + + "The specific key size " + keySize + " is not supported"); + } + if (keySize > maxKeySize) { + throw new InvalidAlgorithmParameterException(algorithm + + " key must be at most " + maxKeySize + " bits. " + + "The specific key size " + keySize + " is not supported"); + } + + // check our own algorithm-specific limits also + if (algorithm.equals("EC")) { + if (keySize < 112) { + throw new InvalidAlgorithmParameterException( + "EC key size must be at least 112 bit. " + + "The specific key size " + keySize + " is not supported"); + } + if (keySize > 2048) { + // sanity check, nobody really wants keys this large + throw new InvalidAlgorithmParameterException( + "EC key size must be at most 2048 bit. " + + "The specific key size " + keySize + " is not supported"); + } + } else { + // RSA, DH, DSA + if (keySize < 512) { + throw new InvalidAlgorithmParameterException(algorithm + + " key size must be at least 512 bit. " + + "The specific key size " + keySize + " is not supported"); + } + if (algorithm.equals("RSA")) { + BigInteger tmpExponent = rsaPublicExponent; + if (params != null) { + tmpExponent = + ((RSAKeyGenParameterSpec)params).getPublicExponent(); + } + try { + RSAKeyFactory.checkKeyLengths(keySize, tmpExponent, + minKeySize, maxKeySize); + } catch (InvalidKeyException e) { + throw new InvalidAlgorithmParameterException(e); + } + } else if (algorithm.equals("DH")) { + if (params != null) { // initialized with specified parameters + // sanity check, nobody really wants keys this large + if (keySize > 64 * 1024) { + throw new InvalidAlgorithmParameterException( + "DH key size must be at most 65536 bit. " + + "The specific key size " + + keySize + " is not supported"); + } + } else { // default parameters will be used. + // Range is based on the values in + // sun.security.provider.ParameterCache class. + if ((keySize > 8192) || (keySize < 512) || + ((keySize & 0x3f) != 0)) { + throw new InvalidAlgorithmParameterException( + "DH key size must be multiple of 64, and can " + + "only range from 512 to 8192 (inclusive). " + + "The specific key size " + + keySize + " is not supported"); + } + + DHParameterSpec cache = + ParameterCache.getCachedDHParameterSpec(keySize); + // Except 2048 and 3072, not yet support generation of + // parameters bigger than 1024 bits. + if ((cache == null) && (keySize > 1024)) { + throw new InvalidAlgorithmParameterException( + "Unsupported " + keySize + + "-bit DH parameter generation"); + } + } + } else { + // this restriction is in the spec for DSA + if ((keySize != 3072) && (keySize != 2048) && + ((keySize > 1024) || ((keySize & 0x3f) != 0))) { + throw new InvalidAlgorithmParameterException( + "DSA key must be multiples of 64 if less than " + + "1024 bits, or 2048, 3072 bits. " + + "The specific key size " + + keySize + " is not supported"); + } + } + } + } + + // see JCA spec + @Override + public KeyPair generateKeyPair() { + token.ensureValid(); + CK_ATTRIBUTE[] publicKeyTemplate; + CK_ATTRIBUTE[] privateKeyTemplate; + long keyType; + if (algorithm.equals("RSA")) { + keyType = CKK_RSA; + publicKeyTemplate = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_MODULUS_BITS, keySize), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, rsaPublicExponent), + }; + privateKeyTemplate = new CK_ATTRIBUTE[] { + // empty + }; + } else if (algorithm.equals("DSA")) { + keyType = CKK_DSA; + DSAParameterSpec dsaParams; + if (params == null) { + try { + dsaParams = ParameterCache.getDSAParameterSpec + (keySize, random); + } catch (GeneralSecurityException e) { + throw new ProviderException + ("Could not generate DSA parameters", e); + } + } else { + dsaParams = (DSAParameterSpec)params; + } + publicKeyTemplate = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_PRIME, dsaParams.getP()), + new CK_ATTRIBUTE(CKA_SUBPRIME, dsaParams.getQ()), + new CK_ATTRIBUTE(CKA_BASE, dsaParams.getG()), + }; + privateKeyTemplate = new CK_ATTRIBUTE[] { + // empty + }; + } else if (algorithm.equals("DH")) { + keyType = CKK_DH; + DHParameterSpec dhParams; + int privateBits; + if (params == null) { + try { + dhParams = ParameterCache.getDHParameterSpec + (keySize, random); + } catch (GeneralSecurityException e) { + throw new ProviderException + ("Could not generate DH parameters", e); + } + privateBits = 0; + } else { + dhParams = (DHParameterSpec)params; + privateBits = dhParams.getL(); + } + if (privateBits <= 0) { + // XXX find better defaults + privateBits = (keySize >= 1024) ? 768 : 512; + } + publicKeyTemplate = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_PRIME, dhParams.getP()), + new CK_ATTRIBUTE(CKA_BASE, dhParams.getG()) + }; + privateKeyTemplate = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_VALUE_BITS, privateBits), + }; + } else if (algorithm.equals("EC")) { + keyType = CKK_EC; + byte[] encodedParams = + P11ECKeyFactory.encodeParameters((ECParameterSpec)params); + publicKeyTemplate = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), + }; + privateKeyTemplate = new CK_ATTRIBUTE[] { + // empty + }; + } else { + throw new ProviderException("Unknown algorithm: " + algorithm); + } + Session session = null; + try { + session = token.getObjSession(); + publicKeyTemplate = token.getAttributes + (O_GENERATE, CKO_PUBLIC_KEY, keyType, publicKeyTemplate); + privateKeyTemplate = token.getAttributes + (O_GENERATE, CKO_PRIVATE_KEY, keyType, privateKeyTemplate); + long[] keyIDs = token.p11.C_GenerateKeyPair + (session.id(), new CK_MECHANISM(mechanism), + publicKeyTemplate, privateKeyTemplate); + PublicKey publicKey = P11Key.publicKey + (session, keyIDs[0], algorithm, keySize, publicKeyTemplate); + PrivateKey privateKey = P11Key.privateKey + (session, keyIDs[1], algorithm, keySize, privateKeyTemplate); + return new KeyPair(publicKey, privateKey); + } catch (PKCS11Exception e) { + throw new ProviderException(e); + } finally { + token.releaseSession(session); + } + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11KeyStore.java b/src/main/java/com/sunyard/security/pkcs11/P11KeyStore.java new file mode 100644 index 0000000..9020909 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11KeyStore.java @@ -0,0 +1,2689 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Set; + +import java.security.*; +import java.security.KeyStore.*; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateException; + +import java.security.interfaces.*; +import java.security.spec.*; + +import javax.crypto.SecretKey; +import javax.crypto.interfaces.*; + +import javax.security.auth.x500.X500Principal; +import javax.security.auth.login.LoginException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import sun.security.util.Debug; +import sun.security.util.DerValue; +import sun.security.util.ECUtil; + +import com.sunyard.security.pkcs11.Secmod.*; +import static com.sunyard.security.pkcs11.P11Util.*; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +import sun.security.rsa.RSAKeyFactory; + +final class P11KeyStore extends KeyStoreSpi { + + private static final CK_ATTRIBUTE ATTR_CLASS_CERT = + new CK_ATTRIBUTE(CKA_CLASS, CKO_CERTIFICATE); + private static final CK_ATTRIBUTE ATTR_CLASS_PKEY = + new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY); + private static final CK_ATTRIBUTE ATTR_CLASS_SKEY = + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); + + private static final CK_ATTRIBUTE ATTR_X509_CERT_TYPE = + new CK_ATTRIBUTE(CKA_CERTIFICATE_TYPE, CKC_X_509); + + private static final CK_ATTRIBUTE ATTR_TOKEN_TRUE = + new CK_ATTRIBUTE(CKA_TOKEN, true); + + // XXX for testing purposes only + // - NSS doesn't support persistent secret keys + // (key type gets mangled if secret key is a token key) + // - if debug is turned on, then this is set to false + private static CK_ATTRIBUTE ATTR_SKEY_TOKEN_TRUE = ATTR_TOKEN_TRUE; + + private static final CK_ATTRIBUTE ATTR_TRUSTED_TRUE = + new CK_ATTRIBUTE(CKA_TRUSTED, true); + private static final CK_ATTRIBUTE ATTR_PRIVATE_TRUE = + new CK_ATTRIBUTE(CKA_PRIVATE, true); + + private static final long NO_HANDLE = -1; + private static final long FINDOBJECTS_MAX = 100; + private static final String ALIAS_SEP = "/"; + + private static final boolean NSS_TEST = false; + private static final Debug debug = + Debug.getInstance("pkcs11keystore"); + private static boolean CKA_TRUSTED_SUPPORTED = true; + + private final Token token; + + // If multiple certs are found to share the same CKA_LABEL + // at load time (NSS-style keystore), then the keystore is read + // and the unique keystore aliases are mapped to the entries. + // However, write capabilities are disabled. + private boolean writeDisabled = false; + + // Map of unique keystore aliases to entries in the token + private HashMap aliasMap; + + // whether to use NSS Secmod info for trust attributes + private final boolean useSecmodTrust; + + // if useSecmodTrust == true, which type of trust we are interested in + private Secmod.TrustType nssTrustType; + + /** + * The underlying token may contain multiple certs belonging to the + * same "personality" (for example, a signing cert and encryption cert), + * all sharing the same CKA_LABEL. These must be resolved + * into unique keystore aliases. + * + * In addition, private keys and certs may not have a CKA_LABEL. + * It is assumed that a private key and corresponding certificate + * share the same CKA_ID, and that the CKA_ID is unique across the token. + * The CKA_ID may not be human-readable. + * These pairs must be resolved into unique keystore aliases. + * + * Furthermore, secret keys are assumed to have a CKA_LABEL + * unique across the entire token. + * + * When the KeyStore is loaded, instances of this class are + * created to represent the private keys/secret keys/certs + * that reside on the token. + */ + private static class AliasInfo { + + // CKA_CLASS - entry type + private CK_ATTRIBUTE type = null; + + // CKA_LABEL of cert and secret key + private String label = null; + + // CKA_ID of the private key/cert pair + private byte[] id = null; + + // CKA_TRUSTED - true if cert is trusted + private boolean trusted = false; + + // either end-entity cert or trusted cert depending on 'type' + private X509Certificate cert = null; + + // chain + private X509Certificate chain[] = null; + + // true if CKA_ID for private key and cert match up + private boolean matched = false; + + // SecretKeyEntry + public AliasInfo(String label) { + this.type = ATTR_CLASS_SKEY; + this.label = label; + } + + // PrivateKeyEntry + public AliasInfo(String label, + byte[] id, + boolean trusted, + X509Certificate cert) { + this.type = ATTR_CLASS_PKEY; + this.label = label; + this.id = id; + this.trusted = trusted; + this.cert = cert; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + if (type == ATTR_CLASS_PKEY) { + sb.append("\ttype=[private key]\n"); + } else if (type == ATTR_CLASS_SKEY) { + sb.append("\ttype=[secret key]\n"); + } else if (type == ATTR_CLASS_CERT) { + sb.append("\ttype=[trusted cert]\n"); + } + sb.append("\tlabel=[" + label + "]\n"); + if (id == null) { + sb.append("\tid=[null]\n"); + } else { + sb.append("\tid=" + P11KeyStore.getID(id) + "\n"); + } + sb.append("\ttrusted=[" + trusted + "]\n"); + sb.append("\tmatched=[" + matched + "]\n"); + if (cert == null) { + sb.append("\tcert=[null]\n"); + } else { + sb.append("\tcert=[\tsubject: " + + cert.getSubjectX500Principal() + + "\n\t\tissuer: " + + cert.getIssuerX500Principal() + + "\n\t\tserialNum: " + + cert.getSerialNumber().toString() + + "]"); + } + return sb.toString(); + } + } + + /** + * callback handler for passing password to Provider.login method + */ + private static class PasswordCallbackHandler implements CallbackHandler { + + private char[] password; + + private PasswordCallbackHandler(char[] password) { + if (password != null) { + this.password = password.clone(); + } + } + + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + if (!(callbacks[0] instanceof PasswordCallback)) { + throw new UnsupportedCallbackException(callbacks[0]); + } + PasswordCallback pc = (PasswordCallback)callbacks[0]; + pc.setPassword(password); // this clones the password if not null + } + + protected void finalize() throws Throwable { + if (password != null) { + Arrays.fill(password, ' '); + } + super.finalize(); + } + } + + /** + * getTokenObject return value. + * + * if object is not found, type is set to null. + * otherwise, type is set to the requested type. + */ + private static class THandle { + private final long handle; // token object handle + private final CK_ATTRIBUTE type; // CKA_CLASS + + private THandle(long handle, CK_ATTRIBUTE type) { + this.handle = handle; + this.type = type; + } + } + + P11KeyStore(Token token) { + this.token = token; + this.useSecmodTrust = token.provider.nssUseSecmodTrust; + } + + /** + * Returns the key associated with the given alias. + * The key must have been associated with + * the alias by a call to setKeyEntry, + * or by a call to setEntry with a + * PrivateKeyEntry or SecretKeyEntry. + * + * @param alias the alias name + * @param password the password, which must be null + * + * @return the requested key, or null if the given alias does not exist + * or does not identify a key-related entry. + * + * @exception NoSuchAlgorithmException if the algorithm for recovering the + * key cannot be found + * @exception UnrecoverableKeyException if the key cannot be recovered + */ + public synchronized Key engineGetKey(String alias, char[] password) + throws NoSuchAlgorithmException, UnrecoverableKeyException { + + token.ensureValid(); + if (password != null && !token.config.getKeyStoreCompatibilityMode()) { + throw new NoSuchAlgorithmException("password must be null"); + } + + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo == null || aliasInfo.type == ATTR_CLASS_CERT) { + return null; + } + + Session session = null; + try { + session = token.getOpSession(); + + if (aliasInfo.type == ATTR_CLASS_PKEY) { + THandle h = getTokenObject(session, + aliasInfo.type, + aliasInfo.id, + null); + if (h.type == ATTR_CLASS_PKEY) { + return loadPkey(session, h.handle); + } + } else { + THandle h = getTokenObject(session, + ATTR_CLASS_SKEY, + null, + alias); + if (h.type == ATTR_CLASS_SKEY) { + return loadSkey(session, h.handle); + } + } + + // did not find anything + return null; + } catch (PKCS11Exception | KeyStoreException e) { + throw new ProviderException(e); + } finally { + token.releaseSession(session); + } + } + + /** + * Returns the certificate chain associated with the given alias. + * The certificate chain must have been associated with the alias + * by a call to setKeyEntry, + * or by a call to setEntry with a + * PrivateKeyEntry. + * + * @param alias the alias name + * + * @return the certificate chain (ordered with the user's certificate first + * and the root certificate authority last), or null if the given alias + * does not exist or does not contain a certificate chain + */ + public synchronized Certificate[] engineGetCertificateChain(String alias) { + + token.ensureValid(); + + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo == null || aliasInfo.type != ATTR_CLASS_PKEY) { + return null; + } + return aliasInfo.chain; + } + + /** + * Returns the certificate associated with the given alias. + * + *

If the given alias name identifies an entry + * created by a call to setCertificateEntry, + * or created by a call to setEntry with a + * TrustedCertificateEntry, + * then the trusted certificate contained in that entry is returned. + * + *

If the given alias name identifies an entry + * created by a call to setKeyEntry, + * or created by a call to setEntry with a + * PrivateKeyEntry, + * then the first element of the certificate chain in that entry + * (if a chain exists) is returned. + * + * @param alias the alias name + * + * @return the certificate, or null if the given alias does not exist or + * does not contain a certificate. + */ + public synchronized Certificate engineGetCertificate(String alias) { + token.ensureValid(); + + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo == null) { + return null; + } + return aliasInfo.cert; + } + + /** + * Returns the creation date of the entry identified by the given alias. + * + * @param alias the alias name + * + * @return the creation date of this entry, or null if the given alias does + * not exist + */ + public Date engineGetCreationDate(String alias) { + token.ensureValid(); + throw new ProviderException(new UnsupportedOperationException()); + } + + /** + * Assigns the given key to the given alias, protecting it with the given + * password. + * + *

If the given key is of type java.security.PrivateKey, + * it must be accompanied by a certificate chain certifying the + * corresponding public key. + * + *

If the given alias already exists, the keystore information + * associated with it is overridden by the given key (and possibly + * certificate chain). + * + * @param alias the alias name + * @param key the key to be associated with the alias + * @param password the password to protect the key + * @param chain the certificate chain for the corresponding public + * key (only required if the given key is of type + * java.security.PrivateKey). + * + * @exception KeyStoreException if the given key cannot be protected, or + * this operation fails for some other reason + */ + public synchronized void engineSetKeyEntry(String alias, Key key, + char[] password, + Certificate[] chain) + throws KeyStoreException { + + token.ensureValid(); + checkWrite(); + + if (!(key instanceof PrivateKey) && !(key instanceof SecretKey)) { + throw new KeyStoreException("key must be PrivateKey or SecretKey"); + } else if (key instanceof PrivateKey && chain == null) { + throw new KeyStoreException + ("PrivateKey must be accompanied by non-null chain"); + } else if (key instanceof SecretKey && chain != null) { + throw new KeyStoreException + ("SecretKey must be accompanied by null chain"); + } else if (password != null && + !token.config.getKeyStoreCompatibilityMode()) { + throw new KeyStoreException("Password must be null"); + } + + KeyStore.Entry entry = null; + try { + if (key instanceof PrivateKey) { + entry = new KeyStore.PrivateKeyEntry((PrivateKey)key, chain); + } else if (key instanceof SecretKey) { + entry = new KeyStore.SecretKeyEntry((SecretKey)key); + } + } catch (NullPointerException | IllegalArgumentException e) { + throw new KeyStoreException(e); + } + engineSetEntry(alias, entry, new KeyStore.PasswordProtection(password)); + } + + /** + * Assigns the given key (that has already been protected) to the given + * alias. + * + *

If the protected key is of type + * java.security.PrivateKey, + * it must be accompanied by a certificate chain certifying the + * corresponding public key. + * + *

If the given alias already exists, the keystore information + * associated with it is overridden by the given key (and possibly + * certificate chain). + * + * @param alias the alias name + * @param key the key (in protected format) to be associated with the alias + * @param chain the certificate chain for the corresponding public + * key (only useful if the protected key is of type + * java.security.PrivateKey). + * + * @exception KeyStoreException if this operation fails. + */ + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) + throws KeyStoreException { + token.ensureValid(); + throw new ProviderException(new UnsupportedOperationException()); + } + + /** + * Assigns the given certificate to the given alias. + * + *

If the given alias identifies an existing entry + * created by a call to setCertificateEntry, + * or created by a call to setEntry with a + * TrustedCertificateEntry, + * the trusted certificate in the existing entry + * is overridden by the given certificate. + * + * @param alias the alias name + * @param cert the certificate + * + * @exception KeyStoreException if the given alias already exists and does + * not identify an entry containing a trusted certificate, + * or this operation fails for some other reason. + */ + public synchronized void engineSetCertificateEntry + (String alias, Certificate cert) throws KeyStoreException { + + token.ensureValid(); + checkWrite(); + + if (cert == null) { + throw new KeyStoreException("invalid null certificate"); + } + + KeyStore.Entry entry = null; + entry = new KeyStore.TrustedCertificateEntry(cert); + engineSetEntry(alias, entry, null); + } + + /** + * Deletes the entry identified by the given alias from this keystore. + * + * @param alias the alias name + * + * @exception KeyStoreException if the entry cannot be removed. + */ + public synchronized void engineDeleteEntry(String alias) + throws KeyStoreException { + token.ensureValid(); + + if (token.isWriteProtected()) { + throw new KeyStoreException("token write-protected"); + } + checkWrite(); + deleteEntry(alias); + } + + /** + * XXX - not sure whether to keep this + */ + private boolean deleteEntry(String alias) throws KeyStoreException { + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo != null) { + + aliasMap.remove(alias); + + try { + if (aliasInfo.type == ATTR_CLASS_CERT) { + // trusted certificate entry + return destroyCert(aliasInfo.id); + } else if (aliasInfo.type == ATTR_CLASS_PKEY) { + // private key entry + return destroyPkey(aliasInfo.id) && + destroyChain(aliasInfo.id); + } else if (aliasInfo.type == ATTR_CLASS_SKEY) { + // secret key entry + return destroySkey(alias); + } else { + throw new KeyStoreException("unexpected entry type"); + } + } catch (PKCS11Exception | CertificateException e) { + throw new KeyStoreException(e); + } + } + return false; + } + + /** + * Lists all the alias names of this keystore. + * + * @return enumeration of the alias names + */ + public synchronized Enumeration engineAliases() { + token.ensureValid(); + + // don't want returned enumeration to iterate off actual keySet - + // otherwise applications that iterate and modify the keystore + // may run into concurrent modification problems + return Collections.enumeration(new HashSet(aliasMap.keySet())); + } + + /** + * Checks if the given alias exists in this keystore. + * + * @param alias the alias name + * + * @return true if the alias exists, false otherwise + */ + public synchronized boolean engineContainsAlias(String alias) { + token.ensureValid(); + return aliasMap.containsKey(alias); + } + + /** + * Retrieves the number of entries in this keystore. + * + * @return the number of entries in this keystore + */ + public synchronized int engineSize() { + token.ensureValid(); + return aliasMap.size(); + } + + /** + * Returns true if the entry identified by the given alias + * was created by a call to setKeyEntry, + * or created by a call to setEntry with a + * PrivateKeyEntry or a SecretKeyEntry. + * + * @param alias the alias for the keystore entry to be checked + * + * @return true if the entry identified by the given alias is a + * key-related, false otherwise. + */ + public synchronized boolean engineIsKeyEntry(String alias) { + token.ensureValid(); + + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo == null || aliasInfo.type == ATTR_CLASS_CERT) { + return false; + } + return true; + } + + /** + * Returns true if the entry identified by the given alias + * was created by a call to setCertificateEntry, + * or created by a call to setEntry with a + * TrustedCertificateEntry. + * + * @param alias the alias for the keystore entry to be checked + * + * @return true if the entry identified by the given alias contains a + * trusted certificate, false otherwise. + */ + public synchronized boolean engineIsCertificateEntry(String alias) { + token.ensureValid(); + + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo == null || aliasInfo.type != ATTR_CLASS_CERT) { + return false; + } + return true; + } + + /** + * Returns the (alias) name of the first keystore entry whose certificate + * matches the given certificate. + * + *

This method attempts to match the given certificate with each + * keystore entry. If the entry being considered was + * created by a call to setCertificateEntry, + * or created by a call to setEntry with a + * TrustedCertificateEntry, + * then the given certificate is compared to that entry's certificate. + * + *

If the entry being considered was + * created by a call to setKeyEntry, + * or created by a call to setEntry with a + * PrivateKeyEntry, + * then the given certificate is compared to the first + * element of that entry's certificate chain. + * + * @param cert the certificate to match with. + * + * @return the alias name of the first entry with matching certificate, + * or null if no such entry exists in this keystore. + */ + public synchronized String engineGetCertificateAlias(Certificate cert) { + token.ensureValid(); + Enumeration e = engineAliases(); + while (e.hasMoreElements()) { + String alias = e.nextElement(); + Certificate tokenCert = engineGetCertificate(alias); + if (tokenCert != null && tokenCert.equals(cert)) { + return alias; + } + } + return null; + } + + /** + * engineStore currently is a No-op. + * Entries are stored to the token during engineSetEntry + * + * @param stream this must be null + * @param password this must be null + */ + public synchronized void engineStore(OutputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException { + token.ensureValid(); + if (stream != null && !token.config.getKeyStoreCompatibilityMode()) { + throw new IOException("output stream must be null"); + } + + if (password != null && !token.config.getKeyStoreCompatibilityMode()) { + throw new IOException("password must be null"); + } + } + + /** + * engineStore currently is a No-op. + * Entries are stored to the token during engineSetEntry + * + * @param param this must be null + * + * @exception IllegalArgumentException if the given + * KeyStore.LoadStoreParameter + * input is not null + */ + public synchronized void engineStore(KeyStore.LoadStoreParameter param) + throws IOException, NoSuchAlgorithmException, CertificateException { + token.ensureValid(); + if (param != null) { + throw new IllegalArgumentException + ("LoadStoreParameter must be null"); + } + } + + /** + * Loads the keystore. + * + * @param stream the input stream, which must be null + * @param password the password used to unlock the keystore, + * or null if the token supports a + * CKF_PROTECTED_AUTHENTICATION_PATH + * + * @exception IOException if the given stream is not + * null, if the token supports a + * CKF_PROTECTED_AUTHENTICATION_PATH and a non-null + * password is given, of if the token login operation failed + */ + public synchronized void engineLoad(InputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException { + + token.ensureValid(); + + if (NSS_TEST) { + ATTR_SKEY_TOKEN_TRUE = new CK_ATTRIBUTE(CKA_TOKEN, false); + } + + if (stream != null && !token.config.getKeyStoreCompatibilityMode()) { + throw new IOException("input stream must be null"); + } + + if (useSecmodTrust) { + nssTrustType = Secmod.TrustType.ALL; + } + + try { + if (password == null) { + login(null); + } else { + login(new PasswordCallbackHandler(password)); + } + } catch(LoginException e) { + Throwable cause = e.getCause(); + if (cause instanceof PKCS11Exception) { + PKCS11Exception pe = (PKCS11Exception) cause; + if (pe.getErrorCode() == CKR_PIN_INCORRECT) { + // if password is wrong, the cause of the IOException + // should be an UnrecoverableKeyException + throw new IOException("load failed", + new UnrecoverableKeyException().initCause(e)); + } + } + throw new IOException("load failed", e); + } + + try { + if (mapLabels() == true) { + // CKA_LABELs are shared by multiple certs + writeDisabled = true; + } + if (debug != null) { + dumpTokenMap(); + debug.println("P11KeyStore load. Entry count: " + + aliasMap.size()); + } + } catch (KeyStoreException | PKCS11Exception e) { + throw new IOException("load failed", e); + } + } + + /** + * Loads the keystore using the given + * KeyStore.LoadStoreParameter. + * + *

The LoadStoreParameter.getProtectionParameter() + * method is expected to return a KeyStore.PasswordProtection + * object. The password is retrieved from that object and used + * to unlock the PKCS#11 token. + * + *

If the token supports a CKF_PROTECTED_AUTHENTICATION_PATH + * then the provided password must be null. + * + * @param param the KeyStore.LoadStoreParameter + * + * @exception IllegalArgumentException if the given + * KeyStore.LoadStoreParameter is null, + * or if that parameter returns a null + * ProtectionParameter object. + * input is not recognized + * @exception IOException if the token supports a + * CKF_PROTECTED_AUTHENTICATION_PATH and the provided password + * is non-null, or if the token login operation fails + */ + public synchronized void engineLoad(KeyStore.LoadStoreParameter param) + throws IOException, NoSuchAlgorithmException, + CertificateException { + + token.ensureValid(); + + if (NSS_TEST) { + ATTR_SKEY_TOKEN_TRUE = new CK_ATTRIBUTE(CKA_TOKEN, false); + } + + // if caller wants to pass a NULL password, + // force it to pass a non-NULL PasswordProtection that returns + // a NULL password + + if (param == null) { + throw new IllegalArgumentException + ("invalid null LoadStoreParameter"); + } + if (useSecmodTrust) { + if (param instanceof Secmod.KeyStoreLoadParameter) { + nssTrustType = ((Secmod.KeyStoreLoadParameter)param).getTrustType(); + } else { + nssTrustType = Secmod.TrustType.ALL; + } + } + + CallbackHandler handler; + KeyStore.ProtectionParameter pp = param.getProtectionParameter(); + if (pp instanceof PasswordProtection) { + char[] password = ((PasswordProtection)pp).getPassword(); + if (password == null) { + handler = null; + } else { + handler = new PasswordCallbackHandler(password); + } + } else if (pp instanceof CallbackHandlerProtection) { + handler = ((CallbackHandlerProtection)pp).getCallbackHandler(); + } else { + throw new IllegalArgumentException + ("ProtectionParameter must be either " + + "PasswordProtection or CallbackHandlerProtection"); + } + + try { + login(handler); + if (mapLabels() == true) { + // CKA_LABELs are shared by multiple certs + writeDisabled = true; + } + if (debug != null) { + dumpTokenMap(); + } + } catch (LoginException | KeyStoreException | PKCS11Exception e) { + throw new IOException("load failed", e); + } + } + + private void login(CallbackHandler handler) throws LoginException { + if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) { + token.provider.login(null, handler); + } else { + // token supports protected authentication path + // (external pin-pad, for example) + if (handler != null && + !token.config.getKeyStoreCompatibilityMode()) { + throw new LoginException("can not specify password if token " + + "supports protected authentication path"); + } + + // must rely on application-set or default handler + // if one is necessary + token.provider.login(null, null); + } + } + + /** + * Get a KeyStore.Entry for the specified alias + * + * @param alias get the KeyStore.Entry for this alias + * @param protParam this must be null + * + * @return the KeyStore.Entry for the specified alias, + * or null if there is no such entry + * + * @exception KeyStoreException if the operation failed + * @exception NoSuchAlgorithmException if the algorithm for recovering the + * entry cannot be found + * @exception UnrecoverableEntryException if the specified + * protParam were insufficient or invalid + * + * @since 1.5 + */ + public synchronized KeyStore.Entry engineGetEntry(String alias, + KeyStore.ProtectionParameter protParam) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableEntryException { + + token.ensureValid(); + + if (protParam != null && + protParam instanceof KeyStore.PasswordProtection && + ((KeyStore.PasswordProtection)protParam).getPassword() != null && + !token.config.getKeyStoreCompatibilityMode()) { + throw new KeyStoreException("ProtectionParameter must be null"); + } + + AliasInfo aliasInfo = aliasMap.get(alias); + if (aliasInfo == null) { + if (debug != null) { + debug.println("engineGetEntry did not find alias [" + + alias + + "] in map"); + } + return null; + } + + Session session = null; + try { + session = token.getOpSession(); + + if (aliasInfo.type == ATTR_CLASS_CERT) { + // trusted certificate entry + if (debug != null) { + debug.println("engineGetEntry found trusted cert entry"); + } + return new KeyStore.TrustedCertificateEntry(aliasInfo.cert); + } else if (aliasInfo.type == ATTR_CLASS_SKEY) { + // secret key entry + if (debug != null) { + debug.println("engineGetEntry found secret key entry"); + } + + THandle h = getTokenObject + (session, ATTR_CLASS_SKEY, null, aliasInfo.label); + if (h.type != ATTR_CLASS_SKEY) { + throw new KeyStoreException + ("expected but could not find secret key"); + } else { + SecretKey skey = loadSkey(session, h.handle); + return new KeyStore.SecretKeyEntry(skey); + } + } else { + // private key entry + if (debug != null) { + debug.println("engineGetEntry found private key entry"); + } + + THandle h = getTokenObject + (session, ATTR_CLASS_PKEY, aliasInfo.id, null); + if (h.type != ATTR_CLASS_PKEY) { + throw new KeyStoreException + ("expected but could not find private key"); + } else { + PrivateKey pkey = loadPkey(session, h.handle); + Certificate[] chain = aliasInfo.chain; + if ((pkey != null) && (chain != null)) { + return new KeyStore.PrivateKeyEntry(pkey, chain); + } else { + if (debug != null) { + debug.println + ("engineGetEntry got null cert chain or private key"); + } + } + } + } + return null; + } catch (PKCS11Exception pe) { + throw new KeyStoreException(pe); + } finally { + token.releaseSession(session); + } + } + + /** + * Save a KeyStore.Entry under the specified alias. + * + *

If an entry already exists for the specified alias, + * it is overridden. + * + *

This KeyStore implementation only supports the standard + * entry types, and only supports X509Certificates in + * TrustedCertificateEntries. Also, this implementation does not support + * protecting entries using a different password + * from the one used for token login. + * + *

Entries are immediately stored on the token. + * + * @param alias save the KeyStore.Entry under this alias + * @param entry the Entry to save + * @param protParam this must be null + * + * @exception KeyStoreException if this operation fails + * + * @since 1.5 + */ + public synchronized void engineSetEntry(String alias, KeyStore.Entry entry, + KeyStore.ProtectionParameter protParam) + throws KeyStoreException { + + token.ensureValid(); + checkWrite(); + + if (protParam != null && + protParam instanceof KeyStore.PasswordProtection && + ((KeyStore.PasswordProtection)protParam).getPassword() != null && + !token.config.getKeyStoreCompatibilityMode()) { + throw new KeyStoreException(new UnsupportedOperationException + ("ProtectionParameter must be null")); + } + + if (token.isWriteProtected()) { + throw new KeyStoreException("token write-protected"); + } + + if (entry instanceof KeyStore.TrustedCertificateEntry) { + + if (useSecmodTrust == false) { + // PKCS #11 does not allow app to modify trusted certs - + throw new KeyStoreException(new UnsupportedOperationException + ("trusted certificates may only be set by " + + "token initialization application")); + } + Module module = token.provider.nssModule; + if ((module.type != ModuleType.KEYSTORE) && (module.type != ModuleType.FIPS)) { + // XXX allow TRUSTANCHOR module + throw new KeyStoreException("Trusted certificates can only be " + + "added to the NSS KeyStore module"); + } + Certificate cert = ((TrustedCertificateEntry)entry).getTrustedCertificate(); + if (cert instanceof X509Certificate == false) { + throw new KeyStoreException("Certificate must be an X509Certificate"); + } + X509Certificate xcert = (X509Certificate)cert; + AliasInfo info = aliasMap.get(alias); + if (info != null) { + // XXX try to update + deleteEntry(alias); + } + try { + storeCert(alias, xcert); + module.setTrust(token, xcert); + mapLabels(); + } catch (PKCS11Exception | CertificateException e) { + throw new KeyStoreException(e); + } + + } else { + + if (entry instanceof KeyStore.PrivateKeyEntry) { + + PrivateKey key = + ((KeyStore.PrivateKeyEntry)entry).getPrivateKey(); + if (!(key instanceof P11Key) && + !(key instanceof RSAPrivateKey) && + !(key instanceof DSAPrivateKey) && + !(key instanceof DHPrivateKey) && + !(key instanceof ECPrivateKey)) { + throw new KeyStoreException("unsupported key type: " + + key.getClass().getName()); + } + + // only support X509Certificate chains + Certificate[] chain = + ((KeyStore.PrivateKeyEntry)entry).getCertificateChain(); + if (!(chain instanceof X509Certificate[])) { + throw new KeyStoreException + (new UnsupportedOperationException + ("unsupported certificate array type: " + + chain.getClass().getName())); + } + + try { + boolean updatedAlias = false; + Set aliases = aliasMap.keySet(); + for (String oldAlias : aliases) { + + // see if there's an existing entry with the same info + + AliasInfo aliasInfo = aliasMap.get(oldAlias); + if (aliasInfo.type == ATTR_CLASS_PKEY && + aliasInfo.cert.getPublicKey().equals + (chain[0].getPublicKey())) { + + // found existing entry - + // caller is renaming entry or updating cert chain + // + // set new CKA_LABEL/CKA_ID + // and update certs if necessary + + updatePkey(alias, + aliasInfo.id, + (X509Certificate[])chain, + !aliasInfo.cert.equals(chain[0])); + updatedAlias = true; + break; + } + } + + if (!updatedAlias) { + // caller adding new entry + engineDeleteEntry(alias); + storePkey(alias, (KeyStore.PrivateKeyEntry)entry); + } + + } catch (PKCS11Exception | CertificateException pe) { + throw new KeyStoreException(pe); + } + + } else if (entry instanceof KeyStore.SecretKeyEntry) { + + KeyStore.SecretKeyEntry ske = (KeyStore.SecretKeyEntry)entry; + SecretKey skey = ske.getSecretKey(); + + try { + // first check if the key already exists + AliasInfo aliasInfo = aliasMap.get(alias); + + if (aliasInfo != null) { + engineDeleteEntry(alias); + } + storeSkey(alias, ske); + + } catch (PKCS11Exception pe) { + throw new KeyStoreException(pe); + } + + } else { + throw new KeyStoreException(new UnsupportedOperationException + ("unsupported entry type: " + entry.getClass().getName())); + } + + try { + + // XXX NSS does not write out the CKA_ID we pass to them + // + // therefore we must re-map labels + // (can not simply update aliasMap) + + mapLabels(); + if (debug != null) { + dumpTokenMap(); + } + } catch (PKCS11Exception | CertificateException pe) { + throw new KeyStoreException(pe); + } + } + + if (debug != null) { + debug.println + ("engineSetEntry added new entry for [" + + alias + + "] to token"); + } + } + + /** + * Determines if the keystore Entry for the specified + * alias is an instance or subclass of the specified + * entryClass. + * + * @param alias the alias name + * @param entryClass the entry class + * + * @return true if the keystore Entry for the specified + * alias is an instance or subclass of the + * specified entryClass, false otherwise + */ + public synchronized boolean engineEntryInstanceOf + (String alias, Class entryClass) { + token.ensureValid(); + return super.engineEntryInstanceOf(alias, entryClass); + } + + private X509Certificate loadCert(Session session, long oHandle) + throws PKCS11Exception, CertificateException { + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] + { new CK_ATTRIBUTE(CKA_VALUE) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + + byte[] bytes = attrs[0].getByteArray(); + if (bytes == null) { + throw new CertificateException + ("unexpectedly retrieved null byte array"); + } + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509Certificate)cf.generateCertificate + (new ByteArrayInputStream(bytes)); + } + + private X509Certificate[] loadChain(Session session, + X509Certificate endCert) + throws PKCS11Exception, CertificateException { + + ArrayList lChain = null; + + if (endCert.getSubjectX500Principal().equals + (endCert.getIssuerX500Principal())) { + // self signed + return new X509Certificate[] { endCert }; + } else { + lChain = new ArrayList(); + lChain.add(endCert); + } + + // try loading remaining certs in chain by following + // issuer->subject links + + X509Certificate next = endCert; + while (true) { + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_CERT, + new CK_ATTRIBUTE(CKA_SUBJECT, + next.getIssuerX500Principal().getEncoded()) }; + long[] ch = findObjects(session, attrs); + + if (ch == null || ch.length == 0) { + // done + break; + } else { + // if more than one found, use first + if (debug != null && ch.length > 1) { + debug.println("engineGetEntry found " + + ch.length + + " certificate entries for subject [" + + next.getIssuerX500Principal().toString() + + "] in token - using first entry"); + } + + next = loadCert(session, ch[0]); + lChain.add(next); + if (next.getSubjectX500Principal().equals + (next.getIssuerX500Principal())) { + // self signed + break; + } + } + } + + return lChain.toArray(new X509Certificate[lChain.size()]); + } + + private SecretKey loadSkey(Session session, long oHandle) + throws PKCS11Exception { + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_KEY_TYPE) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + long kType = attrs[0].getLong(); + + String keyType = null; + int keyLength = -1; + + // XXX NSS mangles the stored key type for secret key token objects + + if (kType == CKK_DES || kType == CKK_DES3) { + if (kType == CKK_DES) { + keyType = "DES"; + keyLength = 64; + } else if (kType == CKK_DES3) { + keyType = "DESede"; + keyLength = 192; + } + } else { + if (kType == CKK_AES) { + keyType = "AES"; + } else if (kType == CKK_BLOWFISH) { + keyType = "Blowfish"; + } else if (kType == CKK_RC4) { + keyType = "ARCFOUR"; + } else { + if (debug != null) { + debug.println("unknown key type [" + + kType + + "] - using 'Generic Secret'"); + } + keyType = "Generic Secret"; + } + + // XXX NSS problem CKR_ATTRIBUTE_TYPE_INVALID? + if (NSS_TEST) { + keyLength = 128; + } else { + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE_LEN) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + keyLength = (int)attrs[0].getLong(); + } + } + + return P11Key.secretKey(session, oHandle, keyType, keyLength, null); + } + + private PrivateKey loadPkey(Session session, long oHandle) + throws PKCS11Exception, KeyStoreException { + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_KEY_TYPE) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + long kType = attrs[0].getLong(); + String keyType = null; + int keyLength = 0; + + if (kType == CKK_RSA) { + + keyType = "RSA"; + + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_MODULUS) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + BigInteger modulus = attrs[0].getBigInteger(); + keyLength = modulus.bitLength(); + + // This check will combine our "don't care" values here + // with the system-wide min/max values. + try { + RSAKeyFactory.checkKeyLengths(keyLength, null, + -1, Integer.MAX_VALUE); + } catch (InvalidKeyException e) { + throw new KeyStoreException(e.getMessage()); + } + + return P11Key.privateKey(session, + oHandle, + keyType, + keyLength, + null); + + } else if (kType == CKK_DSA) { + + keyType = "DSA"; + + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_PRIME) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + BigInteger prime = attrs[0].getBigInteger(); + keyLength = prime.bitLength(); + + return P11Key.privateKey(session, + oHandle, + keyType, + keyLength, + null); + + } else if (kType == CKK_DH) { + + keyType = "DH"; + + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_PRIME) }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + BigInteger prime = attrs[0].getBigInteger(); + keyLength = prime.bitLength(); + + return P11Key.privateKey(session, + oHandle, + keyType, + keyLength, + null); + + } else if (kType == CKK_EC) { + + attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_EC_PARAMS), + }; + token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); + byte[] encodedParams = attrs[0].getByteArray(); + try { + ECParameterSpec params = + ECUtil.getECParameterSpec(null, encodedParams); + keyLength = params.getCurve().getField().getFieldSize(); + } catch (IOException e) { + // we do not want to accept key with unsupported parameters + throw new KeyStoreException("Unsupported parameters", e); + } + + return P11Key.privateKey(session, oHandle, "EC", keyLength, null); + + } else { + if (debug != null) { + debug.println("unknown key type [" + kType + "]"); + } + throw new KeyStoreException("unknown key type"); + } + } + + + /** + * XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key + * it not only changes the CKA_ID of the private key, + * it changes the CKA_ID of the corresponding cert too. + * And vice versa. + * + * XXX On ibutton, CKR_DEVICE_ERROR if you C_SetAttribute(CKA_ID) + * for a private key, and then try to delete the corresponding cert. + * So this code reverses the order. + * After the cert is first destroyed (if necessary), + * then the CKA_ID of the private key can be changed successfully. + * + * @param replaceCert if true, then caller is updating alias info for + * existing cert (only update CKA_ID/CKA_LABEL). + * if false, then caller is updating cert chain + * (delete old end cert and add new chain). + */ + private void updatePkey(String alias, + byte[] cka_id, + X509Certificate[] chain, + boolean replaceCert) throws + KeyStoreException, CertificateException, PKCS11Exception { + + // XXX + // + // always set replaceCert to true + // + // NSS does not allow resetting of CKA_LABEL on an existing cert + // (C_SetAttribute call succeeds, but is ignored) + + replaceCert = true; + + Session session = null; + try { + session = token.getOpSession(); + + // first get private key object handle and hang onto it + + THandle h = getTokenObject(session, ATTR_CLASS_PKEY, cka_id, null); + long pKeyHandle; + if (h.type == ATTR_CLASS_PKEY) { + pKeyHandle = h.handle; + } else { + throw new KeyStoreException + ("expected but could not find private key " + + "with CKA_ID " + + getID(cka_id)); + } + + // next find existing end entity cert + + h = getTokenObject(session, ATTR_CLASS_CERT, cka_id, null); + if (h.type != ATTR_CLASS_CERT) { + throw new KeyStoreException + ("expected but could not find certificate " + + "with CKA_ID " + + getID(cka_id)); + } else { + if (replaceCert) { + // replacing existing cert and chain + destroyChain(cka_id); + } else { + // renaming alias for existing cert + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_LABEL, alias), + new CK_ATTRIBUTE(CKA_ID, alias) }; + token.p11.C_SetAttributeValue + (session.id(), h.handle, attrs); + } + } + + // add new chain + + if (replaceCert) { + // add all certs in chain + storeChain(alias, chain); + } else { + // already updated alias info for existing end cert - + // just update CA certs + storeCaCerts(chain, 1); + } + + // finally update CKA_ID for private key + // + // ibutton may have already done this (that is ok) + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_ID, alias) }; + token.p11.C_SetAttributeValue(session.id(), pKeyHandle, attrs); + + if (debug != null) { + debug.println("updatePkey set new alias [" + + alias + + "] for private key entry"); + } + } finally { + token.releaseSession(session); + } + } + + // retrieves the native key handle and either update it directly or make a copy + private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key) + throws PKCS11Exception { + + // if token key, update alias. + // if session key, convert to token key. + + Session session = null; + long keyID = key.getKeyID(); + try { + session = token.getOpSession(); + if (key.tokenObject == true) { + // token key - set new CKA_ID + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_ID, alias) }; + token.p11.C_SetAttributeValue + (session.id(), keyID, attrs); + if (debug != null) { + debug.println("updateP11Pkey set new alias [" + + alias + + "] for key entry"); + } + } else { + // session key - convert to token key and set CKA_ID + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + new CK_ATTRIBUTE(CKA_ID, alias), + }; + if (attribute != null) { + attrs = addAttribute(attrs, attribute); + } + // creates a new token key with the desired CKA_ID + token.p11.C_CopyObject(session.id(), keyID, attrs); + if (debug != null) { + debug.println("updateP11Pkey copied private session key " + + "for [" + + alias + + "] to token entry"); + } + } + } finally { + token.releaseSession(session); + key.releaseKeyID(); + } + } + + private void storeCert(String alias, X509Certificate cert) + throws PKCS11Exception, CertificateException { + + ArrayList attrList = new ArrayList(); + attrList.add(ATTR_TOKEN_TRUE); + attrList.add(ATTR_CLASS_CERT); + attrList.add(ATTR_X509_CERT_TYPE); + attrList.add(new CK_ATTRIBUTE(CKA_SUBJECT, + cert.getSubjectX500Principal().getEncoded())); + attrList.add(new CK_ATTRIBUTE(CKA_ISSUER, + cert.getIssuerX500Principal().getEncoded())); + attrList.add(new CK_ATTRIBUTE(CKA_SERIAL_NUMBER, + cert.getSerialNumber().toByteArray())); + attrList.add(new CK_ATTRIBUTE(CKA_VALUE, cert.getEncoded())); + + if (alias != null) { + attrList.add(new CK_ATTRIBUTE(CKA_LABEL, alias)); + attrList.add(new CK_ATTRIBUTE(CKA_ID, alias)); + } else { + // ibutton requires something to be set + // - alias must be unique + attrList.add(new CK_ATTRIBUTE(CKA_ID, + getID(cert.getSubjectX500Principal().getName + (X500Principal.CANONICAL), cert))); + } + + Session session = null; + try { + session = token.getOpSession(); + token.p11.C_CreateObject(session.id(), + attrList.toArray(new CK_ATTRIBUTE[attrList.size()])); + } finally { + token.releaseSession(session); + } + } + + private void storeChain(String alias, X509Certificate[] chain) + throws PKCS11Exception, CertificateException { + + // add new chain + // + // end cert has CKA_LABEL and CKA_ID set to alias. + // other certs in chain have neither set. + + storeCert(alias, chain[0]); + storeCaCerts(chain, 1); + } + + private void storeCaCerts(X509Certificate[] chain, int start) + throws PKCS11Exception, CertificateException { + + // do not add duplicate CA cert if already in token + // + // XXX ibutton stores duplicate CA certs, NSS does not + + Session session = null; + HashSet cacerts = new HashSet(); + try { + session = token.getOpSession(); + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_CERT }; + long[] handles = findObjects(session, attrs); + + // load certs currently on the token + for (long handle : handles) { + cacerts.add(loadCert(session, handle)); + } + } finally { + token.releaseSession(session); + } + + for (int i = start; i < chain.length; i++) { + if (!cacerts.contains(chain[i])) { + storeCert(null, chain[i]); + } else if (debug != null) { + debug.println("ignoring duplicate CA cert for [" + + chain[i].getSubjectX500Principal() + + "]"); + } + } + } + + private void storeSkey(String alias, KeyStore.SecretKeyEntry ske) + throws PKCS11Exception, KeyStoreException { + + SecretKey skey = ske.getSecretKey(); + // No need to specify CKA_CLASS, CKA_KEY_TYPE, CKA_VALUE since + // they are handled in P11SecretKeyFactory.createKey() method. + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + ATTR_SKEY_TOKEN_TRUE, + ATTR_PRIVATE_TRUE, + new CK_ATTRIBUTE(CKA_LABEL, alias), + }; + try { + P11SecretKeyFactory.convertKey(token, skey, null, attrs); + } catch (InvalidKeyException ike) { + // re-throw KeyStoreException to match javadoc + throw new KeyStoreException("Cannot convert to PKCS11 keys", ike); + } + + // update global alias map + aliasMap.put(alias, new AliasInfo(alias)); + + if (debug != null) { + debug.println("storeSkey created token secret key for [" + + alias + "]"); + } + } + + private static CK_ATTRIBUTE[] addAttribute(CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE attr) { + int n = attrs.length; + CK_ATTRIBUTE[] newAttrs = new CK_ATTRIBUTE[n + 1]; + System.arraycopy(attrs, 0, newAttrs, 0, n); + newAttrs[n] = attr; + return newAttrs; + } + + private void storePkey(String alias, KeyStore.PrivateKeyEntry pke) + throws PKCS11Exception, CertificateException, KeyStoreException { + + PrivateKey key = pke.getPrivateKey(); + CK_ATTRIBUTE[] attrs = null; + + // If the key is a token object on this token, update it instead + // of creating a duplicate key object. + // Otherwise, treat a P11Key like any other key, if is is extractable. + if (key instanceof P11Key) { + P11Key p11Key = (P11Key)key; + if (p11Key.tokenObject && (p11Key.token == this.token)) { + updateP11Pkey(alias, null, p11Key); + storeChain(alias, (X509Certificate[])pke.getCertificateChain()); + return; + } + } + + boolean useNDB = token.config.getNssNetscapeDbWorkaround(); + PublicKey publicKey = pke.getCertificate().getPublicKey(); + + if (key instanceof RSAPrivateKey) { + + X509Certificate cert = (X509Certificate)pke.getCertificate(); + attrs = getRsaPrivKeyAttrs + (alias, (RSAPrivateKey)key, cert.getSubjectX500Principal()); + + } else if (key instanceof DSAPrivateKey) { + + DSAPrivateKey dsaKey = (DSAPrivateKey)key; + + CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, useNDB); + if (idAttrs[0] == null) { + idAttrs[0] = new CK_ATTRIBUTE(CKA_ID, alias); + } + + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_PKEY, + ATTR_PRIVATE_TRUE, + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DSA), + idAttrs[0], + new CK_ATTRIBUTE(CKA_PRIME, dsaKey.getParams().getP()), + new CK_ATTRIBUTE(CKA_SUBPRIME, dsaKey.getParams().getQ()), + new CK_ATTRIBUTE(CKA_BASE, dsaKey.getParams().getG()), + new CK_ATTRIBUTE(CKA_VALUE, dsaKey.getX()), + }; + if (idAttrs[1] != null) { + attrs = addAttribute(attrs, idAttrs[1]); + } + + attrs = token.getAttributes + (TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_DSA, attrs); + + if (debug != null) { + debug.println("storePkey created DSA template"); + } + + } else if (key instanceof DHPrivateKey) { + + DHPrivateKey dhKey = (DHPrivateKey)key; + + CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, useNDB); + if (idAttrs[0] == null) { + idAttrs[0] = new CK_ATTRIBUTE(CKA_ID, alias); + } + + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_PKEY, + ATTR_PRIVATE_TRUE, + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH), + idAttrs[0], + new CK_ATTRIBUTE(CKA_PRIME, dhKey.getParams().getP()), + new CK_ATTRIBUTE(CKA_BASE, dhKey.getParams().getG()), + new CK_ATTRIBUTE(CKA_VALUE, dhKey.getX()), + }; + if (idAttrs[1] != null) { + attrs = addAttribute(attrs, idAttrs[1]); + } + + attrs = token.getAttributes + (TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_DH, attrs); + + } else if (key instanceof ECPrivateKey) { + + ECPrivateKey ecKey = (ECPrivateKey)key; + + CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, useNDB); + if (idAttrs[0] == null) { + idAttrs[0] = new CK_ATTRIBUTE(CKA_ID, alias); + } + + byte[] encodedParams = + ECUtil.encodeECParameterSpec(null, ecKey.getParams()); + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_PKEY, + ATTR_PRIVATE_TRUE, + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), + idAttrs[0], + new CK_ATTRIBUTE(CKA_VALUE, ecKey.getS()), + new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), + }; + if (idAttrs[1] != null) { + attrs = addAttribute(attrs, idAttrs[1]); + } + + attrs = token.getAttributes + (TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attrs); + + if (debug != null) { + debug.println("storePkey created EC template"); + } + + } else if (key instanceof P11Key) { + // sensitive/non-extractable P11Key + P11Key p11Key = (P11Key)key; + if (p11Key.token != this.token) { + throw new KeyStoreException + ("Cannot move sensitive keys across tokens"); + } + CK_ATTRIBUTE netscapeDB = null; + if (useNDB) { + // Note that this currently fails due to an NSS bug. + // They do not allow the CKA_NETSCAPE_DB attribute to be + // specified during C_CopyObject() and fail with + // CKR_ATTRIBUTE_READ_ONLY. + // But if we did not specify it, they would fail with + // CKA_TEMPLATE_INCOMPLETE, so leave this code in here. + CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, true); + netscapeDB = idAttrs[1]; + } + // Update the key object. + updateP11Pkey(alias, netscapeDB, p11Key); + storeChain(alias, (X509Certificate[])pke.getCertificateChain()); + return; + + } else { + throw new KeyStoreException("unsupported key type: " + key); + } + + Session session = null; + try { + session = token.getOpSession(); + + // create private key entry + token.p11.C_CreateObject(session.id(), attrs); + if (debug != null) { + debug.println("storePkey created token key for [" + + alias + + "]"); + } + } finally { + token.releaseSession(session); + } + + storeChain(alias, (X509Certificate[])pke.getCertificateChain()); + } + + private CK_ATTRIBUTE[] getRsaPrivKeyAttrs(String alias, + RSAPrivateKey key, + X500Principal subject) throws PKCS11Exception { + + // subject is currently ignored - could be used to set CKA_SUBJECT + + CK_ATTRIBUTE[] attrs = null; + if (key instanceof RSAPrivateCrtKey) { + + if (debug != null) { + debug.println("creating RSAPrivateCrtKey attrs"); + } + + RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key; + + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_PKEY, + ATTR_PRIVATE_TRUE, + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), + new CK_ATTRIBUTE(CKA_ID, alias), + new CK_ATTRIBUTE(CKA_MODULUS, + rsaKey.getModulus()), + new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, + rsaKey.getPrivateExponent()), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, + rsaKey.getPublicExponent()), + new CK_ATTRIBUTE(CKA_PRIME_1, + rsaKey.getPrimeP()), + new CK_ATTRIBUTE(CKA_PRIME_2, + rsaKey.getPrimeQ()), + new CK_ATTRIBUTE(CKA_EXPONENT_1, + rsaKey.getPrimeExponentP()), + new CK_ATTRIBUTE(CKA_EXPONENT_2, + rsaKey.getPrimeExponentQ()), + new CK_ATTRIBUTE(CKA_COEFFICIENT, + rsaKey.getCrtCoefficient()) }; + attrs = token.getAttributes + (TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attrs); + + } else { + + if (debug != null) { + debug.println("creating RSAPrivateKey attrs"); + } + + RSAPrivateKey rsaKey = key; + + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_PKEY, + ATTR_PRIVATE_TRUE, + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), + new CK_ATTRIBUTE(CKA_ID, alias), + new CK_ATTRIBUTE(CKA_MODULUS, + rsaKey.getModulus()), + new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, + rsaKey.getPrivateExponent()) }; + attrs = token.getAttributes + (TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attrs); + } + + return attrs; + } + + /** + * Compute the CKA_ID and/or CKA_NETSCAPE_DB attributes that should be + * used for this private key. It uses the same algorithm to calculate the + * values as NSS. The public and private keys MUST match for the result to + * be correct. + * + * It returns a 2 element array with CKA_ID at index 0 and CKA_NETSCAPE_DB + * at index 1. The boolean flags determine what is to be calculated. + * If false or if we could not calculate the value, that element is null. + * + * NOTE that we currently do not use the CKA_ID value calculated by this + * method. + */ + private CK_ATTRIBUTE[] getIdAttributes(PrivateKey privateKey, + PublicKey publicKey, boolean id, boolean netscapeDb) { + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[2]; + if ((id || netscapeDb) == false) { + return attrs; + } + String alg = privateKey.getAlgorithm(); + if (alg.equals("RSA") && (publicKey instanceof RSAPublicKey)) { + if (id) { + BigInteger n = ((RSAPublicKey)publicKey).getModulus(); + attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(n))); + } + // CKA_NETSCAPE_DB not needed for RSA public keys + } else if (alg.equals("DSA") && (publicKey instanceof DSAPublicKey)) { + BigInteger y = ((DSAPublicKey)publicKey).getY(); + if (id) { + attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(y))); + } + if (netscapeDb) { + attrs[1] = new CK_ATTRIBUTE(CKA_NETSCAPE_DB, y); + } + } else if (alg.equals("DH") && (publicKey instanceof DHPublicKey)) { + BigInteger y = ((DHPublicKey)publicKey).getY(); + if (id) { + attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(y))); + } + if (netscapeDb) { + attrs[1] = new CK_ATTRIBUTE(CKA_NETSCAPE_DB, y); + } + } else if (alg.equals("EC") && (publicKey instanceof ECPublicKey)) { + ECPublicKey ecPub = (ECPublicKey)publicKey; + ECPoint point = ecPub.getW(); + ECParameterSpec params = ecPub.getParams(); + byte[] encodedPoint = ECUtil.encodePoint(point, params.getCurve()); + if (id) { + attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(encodedPoint)); + } + if (netscapeDb) { + attrs[1] = new CK_ATTRIBUTE(CKA_NETSCAPE_DB, encodedPoint); + } + } else { + throw new RuntimeException("Unknown key algorithm " + alg); + } + return attrs; + } + + /** + * return true if cert destroyed + */ + private boolean destroyCert(byte[] cka_id) + throws PKCS11Exception, KeyStoreException { + Session session = null; + try { + session = token.getOpSession(); + THandle h = getTokenObject(session, ATTR_CLASS_CERT, cka_id, null); + if (h.type != ATTR_CLASS_CERT) { + return false; + } + + token.p11.C_DestroyObject(session.id(), h.handle); + if (debug != null) { + debug.println("destroyCert destroyed cert with CKA_ID [" + + getID(cka_id) + + "]"); + } + return true; + } finally { + token.releaseSession(session); + } + } + + /** + * return true if chain destroyed + */ + private boolean destroyChain(byte[] cka_id) + throws PKCS11Exception, CertificateException, KeyStoreException { + + Session session = null; + try { + session = token.getOpSession(); + + THandle h = getTokenObject(session, ATTR_CLASS_CERT, cka_id, null); + if (h.type != ATTR_CLASS_CERT) { + if (debug != null) { + debug.println("destroyChain could not find " + + "end entity cert with CKA_ID [0x" + + Functions.toHexString(cka_id) + + "]"); + } + return false; + } + + X509Certificate endCert = loadCert(session, h.handle); + token.p11.C_DestroyObject(session.id(), h.handle); + if (debug != null) { + debug.println("destroyChain destroyed end entity cert " + + "with CKA_ID [" + + getID(cka_id) + + "]"); + } + + // build chain following issuer->subject links + + X509Certificate next = endCert; + while (true) { + + if (next.getSubjectX500Principal().equals + (next.getIssuerX500Principal())) { + // self signed - done + break; + } + + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_CERT, + new CK_ATTRIBUTE(CKA_SUBJECT, + next.getIssuerX500Principal().getEncoded()) }; + long[] ch = findObjects(session, attrs); + + if (ch == null || ch.length == 0) { + // done + break; + } else { + // if more than one found, use first + if (debug != null && ch.length > 1) { + debug.println("destroyChain found " + + ch.length + + " certificate entries for subject [" + + next.getIssuerX500Principal() + + "] in token - using first entry"); + } + + next = loadCert(session, ch[0]); + + // only delete if not part of any other chain + + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_CERT, + new CK_ATTRIBUTE(CKA_ISSUER, + next.getSubjectX500Principal().getEncoded()) }; + long[] issuers = findObjects(session, attrs); + + boolean destroyIt = false; + if (issuers == null || issuers.length == 0) { + // no other certs with this issuer - + // destroy it + destroyIt = true; + } else if (issuers.length == 1) { + X509Certificate iCert = loadCert(session, issuers[0]); + if (next.equals(iCert)) { + // only cert with issuer is itself (self-signed) - + // destroy it + destroyIt = true; + } + } + + if (destroyIt) { + token.p11.C_DestroyObject(session.id(), ch[0]); + if (debug != null) { + debug.println + ("destroyChain destroyed cert in chain " + + "with subject [" + + next.getSubjectX500Principal() + "]"); + } + } else { + if (debug != null) { + debug.println("destroyChain did not destroy " + + "shared cert in chain with subject [" + + next.getSubjectX500Principal() + "]"); + } + } + } + } + + return true; + + } finally { + token.releaseSession(session); + } + } + + /** + * return true if secret key destroyed + */ + private boolean destroySkey(String alias) + throws PKCS11Exception, KeyStoreException { + Session session = null; + try { + session = token.getOpSession(); + + THandle h = getTokenObject(session, ATTR_CLASS_SKEY, null, alias); + if (h.type != ATTR_CLASS_SKEY) { + if (debug != null) { + debug.println("destroySkey did not find secret key " + + "with CKA_LABEL [" + + alias + + "]"); + } + return false; + } + token.p11.C_DestroyObject(session.id(), h.handle); + return true; + } finally { + token.releaseSession(session); + } + } + + /** + * return true if private key destroyed + */ + private boolean destroyPkey(byte[] cka_id) + throws PKCS11Exception, KeyStoreException { + Session session = null; + try { + session = token.getOpSession(); + + THandle h = getTokenObject(session, ATTR_CLASS_PKEY, cka_id, null); + if (h.type != ATTR_CLASS_PKEY) { + if (debug != null) { + debug.println + ("destroyPkey did not find private key with CKA_ID [" + + getID(cka_id) + + "]"); + } + return false; + } + token.p11.C_DestroyObject(session.id(), h.handle); + return true; + } finally { + token.releaseSession(session); + } + } + + /** + * build [alias + issuer + serialNumber] string from a cert + */ + private String getID(String alias, X509Certificate cert) { + X500Principal issuer = cert.getIssuerX500Principal(); + BigInteger serialNum = cert.getSerialNumber(); + + return alias + + ALIAS_SEP + + issuer.getName(X500Principal.CANONICAL) + + ALIAS_SEP + + serialNum.toString(); + } + + /** + * build CKA_ID string from bytes + */ + private static String getID(byte[] bytes) { + boolean printable = true; + for (int i = 0; i < bytes.length; i++) { + if (!DerValue.isPrintableStringChar((char)bytes[i])) { + printable = false; + break; + } + } + + if (!printable) { + return "0x" + Functions.toHexString(bytes); + } else { + try { + return new String(bytes, "UTF-8"); + } catch (UnsupportedEncodingException uee) { + return "0x" + Functions.toHexString(bytes); + } + } + } + + /** + * find an object on the token + * + * @param type either ATTR_CLASS_CERT, ATTR_CLASS_PKEY, or ATTR_CLASS_SKEY + * @param cka_id the CKA_ID if type is ATTR_CLASS_CERT or ATTR_CLASS_PKEY + * @param cka_label the CKA_LABEL if type is ATTR_CLASS_SKEY + */ + private THandle getTokenObject(Session session, + CK_ATTRIBUTE type, + byte[] cka_id, + String cka_label) + throws PKCS11Exception, KeyStoreException { + + CK_ATTRIBUTE[] attrs; + if (type == ATTR_CLASS_SKEY) { + attrs = new CK_ATTRIBUTE[] { + ATTR_SKEY_TOKEN_TRUE, + new CK_ATTRIBUTE(CKA_LABEL, cka_label), + type }; + } else { + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + new CK_ATTRIBUTE(CKA_ID, cka_id), + type }; + } + long[] h = findObjects(session, attrs); + if (h.length == 0) { + if (debug != null) { + if (type == ATTR_CLASS_SKEY) { + debug.println("getTokenObject did not find secret key " + + "with CKA_LABEL [" + + cka_label + + "]"); + } else if (type == ATTR_CLASS_CERT) { + debug.println + ("getTokenObject did not find cert with CKA_ID [" + + getID(cka_id) + + "]"); + } else { + debug.println("getTokenObject did not find private key " + + "with CKA_ID [" + + getID(cka_id) + + "]"); + } + } + } else if (h.length == 1) { + + // found object handle - return it + return new THandle(h[0], type); + + } else { + + // found multiple object handles - + // see if token ignored CKA_LABEL during search (e.g. NSS) + + if (type == ATTR_CLASS_SKEY) { + + ArrayList list = new ArrayList(h.length); + for (int i = 0; i < h.length; i++) { + + CK_ATTRIBUTE[] label = new CK_ATTRIBUTE[] + { new CK_ATTRIBUTE(CKA_LABEL) }; + token.p11.C_GetAttributeValue(session.id(), h[i], label); + if (label[0].pValue != null && + cka_label.equals(new String(label[0].getCharArray()))) { + list.add(new THandle(h[i], ATTR_CLASS_SKEY)); + } + } + if (list.size() == 1) { + // yes, there was only one CKA_LABEL that matched + return list.get(0); + } else { + throw new KeyStoreException("invalid KeyStore state: " + + "found " + + list.size() + + " secret keys sharing CKA_LABEL [" + + cka_label + + "]"); + } + } else if (type == ATTR_CLASS_CERT) { + throw new KeyStoreException("invalid KeyStore state: " + + "found " + + h.length + + " certificates sharing CKA_ID " + + getID(cka_id)); + } else { + throw new KeyStoreException("invalid KeyStore state: " + + "found " + + h.length + + " private keys sharing CKA_ID " + + getID(cka_id)); + } + } + return new THandle(NO_HANDLE, null); + } + + /** + * Create a mapping of all key pairs, trusted certs, and secret keys + * on the token into logical KeyStore entries unambiguously + * accessible via an alias. + * + * If the token is removed, the map may contain stale values. + * KeyStore.load should be called to re-create the map. + * + * Assume all private keys and matching certs share a unique CKA_ID. + * + * Assume all secret keys have a unique CKA_LABEL. + * + * @return true if multiple certs found sharing the same CKA_LABEL + * (if so, write capabilities are disabled) + */ + private boolean mapLabels() throws + PKCS11Exception, CertificateException, KeyStoreException { + + CK_ATTRIBUTE[] trustedAttr = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_TRUSTED) }; + + Session session = null; + try { + session = token.getOpSession(); + + // get all private key CKA_IDs + + ArrayList pkeyIDs = new ArrayList(); + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_PKEY, + }; + long[] handles = findObjects(session, attrs); + + for (long handle : handles) { + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_ID) }; + token.p11.C_GetAttributeValue(session.id(), handle, attrs); + + if (attrs[0].pValue != null) { + pkeyIDs.add(attrs[0].getByteArray()); + } + } + + // Get all certificates + // + // If cert does not have a CKA_LABEL nor CKA_ID, it is ignored. + // + // Get the CKA_LABEL for each cert + // (if the cert does not have a CKA_LABEL, use the CKA_ID). + // + // Map each cert to the its CKA_LABEL + // (multiple certs may be mapped to a single CKA_LABEL) + + HashMap> certMap = + new HashMap>(); + + attrs = new CK_ATTRIBUTE[] { + ATTR_TOKEN_TRUE, + ATTR_CLASS_CERT, + }; + handles = findObjects(session, attrs); + + for (long handle : handles) { + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_LABEL) }; + + String cka_label = null; + byte[] cka_id = null; + try { + token.p11.C_GetAttributeValue(session.id(), handle, attrs); + if (attrs[0].pValue != null) { + // there is a CKA_LABEL + cka_label = new String(attrs[0].getCharArray()); + } + } catch (PKCS11Exception pe) { + if (pe.getErrorCode() != CKR_ATTRIBUTE_TYPE_INVALID) { + throw pe; + } + + // GetAttributeValue for CKA_LABEL not supported + // + // XXX SCA1000 + } + + // get CKA_ID + + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_ID) }; + token.p11.C_GetAttributeValue(session.id(), handle, attrs); + if (attrs[0].pValue == null) { + if (cka_label == null) { + // no cka_label nor cka_id - ignore + continue; + } + } else { + if (cka_label == null) { + // use CKA_ID as CKA_LABEL + cka_label = getID(attrs[0].getByteArray()); + } + cka_id = attrs[0].getByteArray(); + } + + X509Certificate cert = loadCert(session, handle); + + // get CKA_TRUSTED + + boolean cka_trusted = false; + + if (useSecmodTrust) { + cka_trusted = Secmod.getInstance().isTrusted(cert, nssTrustType); + } else { + if (CKA_TRUSTED_SUPPORTED) { + try { + token.p11.C_GetAttributeValue + (session.id(), handle, trustedAttr); + cka_trusted = trustedAttr[0].getBoolean(); + } catch (PKCS11Exception pe) { + if (pe.getErrorCode() == CKR_ATTRIBUTE_TYPE_INVALID) { + // XXX NSS, ibutton, sca1000 + CKA_TRUSTED_SUPPORTED = false; + if (debug != null) { + debug.println + ("CKA_TRUSTED attribute not supported"); + } + } + } + } + } + + HashSet infoSet = certMap.get(cka_label); + if (infoSet == null) { + infoSet = new HashSet(2); + certMap.put(cka_label, infoSet); + } + + // initially create private key entry AliasInfo entries - + // these entries will get resolved into their true + // entry types later + + infoSet.add(new AliasInfo + (cka_label, + cka_id, + cka_trusted, + cert)); + } + + // create list secret key CKA_LABELS - + // if there are duplicates (either between secret keys, + // or between a secret key and another object), + // throw an exception + HashMap sKeyMap = + new HashMap(); + + attrs = new CK_ATTRIBUTE[] { + ATTR_SKEY_TOKEN_TRUE, + ATTR_CLASS_SKEY, + }; + handles = findObjects(session, attrs); + + for (long handle : handles) { + attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_LABEL) }; + token.p11.C_GetAttributeValue(session.id(), handle, attrs); + if (attrs[0].pValue != null) { + + // there is a CKA_LABEL + String cka_label = new String(attrs[0].getCharArray()); + if (sKeyMap.get(cka_label) == null) { + sKeyMap.put(cka_label, new AliasInfo(cka_label)); + } else { + throw new KeyStoreException("invalid KeyStore state: " + + "found multiple secret keys sharing same " + + "CKA_LABEL [" + + cka_label + + "]"); + } + } + } + + // update global aliasMap with alias mappings + ArrayList matchedCerts = + mapPrivateKeys(pkeyIDs, certMap); + boolean sharedLabel = mapCerts(matchedCerts, certMap); + mapSecretKeys(sKeyMap); + + return sharedLabel; + + } finally { + token.releaseSession(session); + } + } + + /** + * for each private key CKA_ID, find corresponding cert with same CKA_ID. + * if found cert, see if cert CKA_LABEL is unique. + * if CKA_LABEL unique, map private key/cert alias to that CKA_LABEL. + * if CKA_LABEL not unique, map private key/cert alias to: + * CKA_LABEL + ALIAS_SEP + ISSUER + ALIAS_SEP + SERIAL + * if cert not found, ignore private key + * (don't support private key entries without a cert chain yet) + * + * @return a list of AliasInfo entries that represents all matches + */ + private ArrayList mapPrivateKeys(ArrayList pkeyIDs, + HashMap> certMap) + throws PKCS11Exception, CertificateException { + + // reset global alias map + aliasMap = new HashMap(); + + // list of matched certs that we will return + ArrayList matchedCerts = new ArrayList(); + + for (byte[] pkeyID : pkeyIDs) { + + // try to find a matching CKA_ID in a certificate + + boolean foundMatch = false; + Set certLabels = certMap.keySet(); + for (String certLabel : certLabels) { + + // get cert CKA_IDs (if present) for each cert + + HashSet infoSet = certMap.get(certLabel); + for (AliasInfo aliasInfo : infoSet) { + if (Arrays.equals(pkeyID, aliasInfo.id)) { + + // found private key with matching cert + + if (infoSet.size() == 1) { + // unique CKA_LABEL - use certLabel as alias + aliasInfo.matched = true; + aliasMap.put(certLabel, aliasInfo); + } else { + // create new alias + aliasInfo.matched = true; + aliasMap.put(getID(certLabel, aliasInfo.cert), + aliasInfo); + } + matchedCerts.add(aliasInfo); + foundMatch = true; + break; + } + } + if (foundMatch) { + break; + } + } + + if (!foundMatch) { + if (debug != null) { + debug.println + ("did not find match for private key with CKA_ID [" + + getID(pkeyID) + + "] (ignoring entry)"); + } + } + } + + return matchedCerts; + } + + /** + * for each cert not matched with a private key but is CKA_TRUSTED: + * if CKA_LABEL unique, map cert to CKA_LABEL. + * if CKA_LABEL not unique, map cert to [label+issuer+serialNum] + * + * if CKA_TRUSTED not supported, treat all certs not part of a chain + * as trusted + * + * @return true if multiple certs found sharing the same CKA_LABEL + */ + private boolean mapCerts(ArrayList matchedCerts, + HashMap> certMap) + throws PKCS11Exception, CertificateException { + + // load all cert chains + for (AliasInfo aliasInfo : matchedCerts) { + Session session = null; + try { + session = token.getOpSession(); + aliasInfo.chain = loadChain(session, aliasInfo.cert); + } finally { + token.releaseSession(session); + } + } + + // find all certs in certMap not part of a cert chain + // - these are trusted + + boolean sharedLabel = false; + + Set certLabels = certMap.keySet(); + for (String certLabel : certLabels) { + HashSet infoSet = certMap.get(certLabel); + for (AliasInfo aliasInfo : infoSet) { + + if (aliasInfo.matched == true) { + // already found a private key match for this cert - + // just continue + aliasInfo.trusted = false; + continue; + } + + // cert in this aliasInfo is not matched yet + // + // if CKA_TRUSTED_SUPPORTED == true, + // then check if cert is trusted + + if (CKA_TRUSTED_SUPPORTED) { + if (aliasInfo.trusted) { + // trusted certificate + if (mapTrustedCert + (certLabel, aliasInfo, infoSet) == true) { + sharedLabel = true; + } + } + continue; + } + + // CKA_TRUSTED_SUPPORTED == false + // + // XXX treat all certs not part of a chain as trusted + // XXX + // XXX Unsupported + // + // boolean partOfChain = false; + // for (AliasInfo matchedInfo : matchedCerts) { + // for (int i = 0; i < matchedInfo.chain.length; i++) { + // if (matchedInfo.chain[i].equals(aliasInfo.cert)) { + // partOfChain = true; + // break; + // } + // } + // if (partOfChain) { + // break; + // } + // } + // + // if (!partOfChain) { + // if (mapTrustedCert(certLabel,aliasInfo,infoSet) == true){ + // sharedLabel = true; + // } + // } else { + // if (debug != null) { + // debug.println("ignoring unmatched/untrusted cert " + + // "that is part of cert chain - cert subject is [" + + // aliasInfo.cert.getSubjectX500Principal().getName + // (X500Principal.CANONICAL) + + // "]"); + // } + // } + } + } + + return sharedLabel; + } + + private boolean mapTrustedCert(String certLabel, + AliasInfo aliasInfo, + HashSet infoSet) { + + boolean sharedLabel = false; + + aliasInfo.type = ATTR_CLASS_CERT; + aliasInfo.trusted = true; + if (infoSet.size() == 1) { + // unique CKA_LABEL - use certLabel as alias + aliasMap.put(certLabel, aliasInfo); + } else { + // create new alias + sharedLabel = true; + aliasMap.put(getID(certLabel, aliasInfo.cert), aliasInfo); + } + + return sharedLabel; + } + + /** + * If the secret key shares a CKA_LABEL with another entry, + * throw an exception + */ + private void mapSecretKeys(HashMap sKeyMap) + throws KeyStoreException { + for (String label : sKeyMap.keySet()) { + if (aliasMap.containsKey(label)) { + throw new KeyStoreException("invalid KeyStore state: " + + "found secret key sharing CKA_LABEL [" + + label + + "] with another token object"); + } + } + aliasMap.putAll(sKeyMap); + } + + private void dumpTokenMap() { + Set aliases = aliasMap.keySet(); + System.out.println("Token Alias Map:"); + if (aliases.isEmpty()) { + System.out.println(" [empty]"); + } else { + for (String s : aliases) { + System.out.println(" " + s + aliasMap.get(s)); + } + } + } + + private void checkWrite() throws KeyStoreException { + if (writeDisabled) { + throw new KeyStoreException + ("This PKCS11KeyStore does not support write capabilities"); + } + } + + private final static long[] LONG0 = new long[0]; + + private static long[] findObjects(Session session, CK_ATTRIBUTE[] attrs) + throws PKCS11Exception { + Token token = session.token; + long[] handles = LONG0; + token.p11.C_FindObjectsInit(session.id(), attrs); + while (true) { + long[] h = token.p11.C_FindObjects(session.id(), FINDOBJECTS_MAX); + if (h.length == 0) { + break; + } + handles = P11Util.concat(handles, h); + } + token.p11.C_FindObjectsFinal(session.id()); + return handles; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11Mac.java b/src/main/java/com/sunyard/security/pkcs11/P11Mac.java new file mode 100644 index 0000000..ab82e4f --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11Mac.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.nio.ByteBuffer; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.MacSpi; + +import sun.nio.ch.DirectBuffer; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * MAC implementation class. This class currently supports HMAC using + * MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 and the SSL3 MAC + * using MD5 and SHA-1. + * + * Note that unlike other classes (e.g. Signature), this does not + * composite various operations if the token only supports part of the + * required functionality. The MAC implementations in SunJCE already + * do exactly that by implementing an MAC on top of MessageDigests. We + * could not do any better than they. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11Mac extends MacSpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism object + private final CK_MECHANISM ckMechanism; + + // length of the MAC in bytes + private final int macLength; + + // key instance used, if operation active + private P11Key p11Key; + + // associated session, if any + private Session session; + + // initialization status + private boolean initialized; + + // one byte buffer for the update(byte) method, initialized on demand + private byte[] oneByte; + + P11Mac(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + Long params = null; + switch ((int)mechanism) { + case (int)CKM_MD5_HMAC: + macLength = 16; + break; + case (int)CKM_SHA_1_HMAC: + macLength = 20; + break; + case (int)CKM_SHA224_HMAC: + case (int)CKM_SHA512_224_HMAC: + macLength = 28; + break; + case (int)CKM_SHA256_HMAC: + case (int)CKM_SHA512_256_HMAC: + macLength = 32; + break; + case (int)CKM_SHA384_HMAC: + macLength = 48; + break; + case (int)CKM_SHA512_HMAC: + macLength = 64; + break; + case (int)CKM_SSL3_MD5_MAC: + macLength = 16; + params = Long.valueOf(16); + break; + case (int)CKM_SSL3_SHA1_MAC: + macLength = 20; + params = Long.valueOf(20); + break; + default: + throw new ProviderException("Unknown mechanism: " + mechanism); + } + ckMechanism = new CK_MECHANISM(mechanism, params); + } + + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + + try { + if (session == null) { + return; + } + + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + } + } + + private void cancelOperation() { + token.ensureValid(); + // cancel operation by finishing it; avoid killSession as some + // hardware vendors may require re-login + try { + token.p11.C_SignFinal(session.id(), 0); + } catch (PKCS11Exception e) { + if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { + // Cancel Operation may be invoked after an error on a PKCS#11 + // call. If the operation inside the token was already cancelled, + // do not fail here. This is part of a defensive mechanism for + // PKCS#11 libraries that do not strictly follow the standard. + return; + } + throw new ProviderException("Cancel failed", e); + } + } + + private void ensureInitialized() throws PKCS11Exception { + if (!initialized) { + initialize(); + } + } + + private void initialize() throws PKCS11Exception { + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without calling engineInit first"); + } + token.ensureValid(); + long p11KeyID = p11Key.getKeyID(); + try { + if (session == null) { + session = token.getOpSession(); + } + token.p11.C_SignInit(session.id(), ckMechanism, p11KeyID); + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw e; + } + initialized = true; + } + + // see JCE spec + protected int engineGetMacLength() { + return macLength; + } + + // see JCE spec + protected void engineReset() { + reset(true); + } + + // see JCE spec + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException + ("Parameters not supported"); + } + reset(true); + p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm); + try { + initialize(); + } catch (PKCS11Exception e) { + throw new InvalidKeyException("init() failed", e); + } + } + + // see JCE spec + protected byte[] engineDoFinal() { + try { + ensureInitialized(); + return token.p11.C_SignFinal(session.id(), 0); + } catch (PKCS11Exception e) { + // As per the PKCS#11 standard, C_SignFinal may only + // keep the operation active on CKR_BUFFER_TOO_SMALL errors or + // successful calls to determine the output length. However, + // these cases are handled at OpenJDK's libj2pkcs11 native + // library. Thus, P11Mac::reset can be called with a 'false' + // doCancel argument from here. + throw new ProviderException("doFinal() failed", e); + } finally { + reset(false); + } + } + + // see JCE spec + protected void engineUpdate(byte input) { + if (oneByte == null) { + oneByte = new byte[1]; + } + oneByte[0] = input; + engineUpdate(oneByte, 0, 1); + } + + // see JCE spec + protected void engineUpdate(byte[] b, int ofs, int len) { + try { + ensureInitialized(); + token.p11.C_SignUpdate(session.id(), 0, b, ofs, len); + } catch (PKCS11Exception e) { + throw new ProviderException("update() failed", e); + } + } + + // see JCE spec + protected void engineUpdate(ByteBuffer byteBuffer) { + try { + ensureInitialized(); + int len = byteBuffer.remaining(); + if (len <= 0) { + return; + } + if (byteBuffer instanceof DirectBuffer == false) { + super.engineUpdate(byteBuffer); + return; + } + long addr = ((DirectBuffer)byteBuffer).address(); + int ofs = byteBuffer.position(); + token.p11.C_SignUpdate(session.id(), addr + ofs, null, 0, len); + byteBuffer.position(ofs + len); + } catch (PKCS11Exception e) { + throw new ProviderException("update() failed", e); + } + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11PSSSignature.java b/src/main/java/com/sunyard/security/pkcs11/P11PSSSignature.java new file mode 100644 index 0000000..edd4689 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11PSSSignature.java @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import sun.nio.ch.DirectBuffer; + +import java.util.Hashtable; +import java.util.Arrays; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.security.interfaces.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + + +/** + * RSASSA-PSS Signature implementation class. This class currently supports the + * following algorithms: + * + * . RSA-PSS: + * . RSASSA-PSS + * . SHA1withRSASSA-PSS + * . SHA224withRSASSA-PSS + * . SHA256withRSASSA-PSS + * . SHA384withRSASSA-PSS + * . SHA512withRSASSA-PSS + * + * Note that the underlying PKCS#11 token may support complete signature + * algorithm (e.g. CKM__RSA_PKCS_PSS), or it may just + * implement the signature algorithm without hashing (i.e. CKM_RSA_PKCS_PSS). + * This class uses what is available and adds whatever extra processing + * is needed. + * + * @since 13 + */ +final class P11PSSSignature extends SignatureSpi { + + private final static boolean DEBUG = false; + + // mappings of digest algorithms and their output length in bytes + private static final Hashtable DIGEST_LENGTHS = + new Hashtable(); + + static { + DIGEST_LENGTHS.put("SHA-1", 20); + DIGEST_LENGTHS.put("SHA", 20); + DIGEST_LENGTHS.put("SHA1", 20); + DIGEST_LENGTHS.put("SHA-224", 28); + DIGEST_LENGTHS.put("SHA224", 28); + DIGEST_LENGTHS.put("SHA-256", 32); + DIGEST_LENGTHS.put("SHA256", 32); + DIGEST_LENGTHS.put("SHA-384", 48); + DIGEST_LENGTHS.put("SHA384", 48); + DIGEST_LENGTHS.put("SHA-512", 64); + DIGEST_LENGTHS.put("SHA512", 64); + DIGEST_LENGTHS.put("SHA-512/224", 28); + DIGEST_LENGTHS.put("SHA512/224", 28); + DIGEST_LENGTHS.put("SHA-512/256", 32); + DIGEST_LENGTHS.put("SHA512/256", 32); + } + + // utility method for comparing digest algorithms + // NOTE that first argument is assumed to be standard digest name + private static boolean isDigestEqual(String stdAlg, String givenAlg) { + if (stdAlg == null || givenAlg == null) return false; + + if (givenAlg.indexOf("-") != -1) { + return stdAlg.equalsIgnoreCase(givenAlg); + } else { + if (stdAlg.equals("SHA-1")) { + return (givenAlg.equalsIgnoreCase("SHA") + || givenAlg.equalsIgnoreCase("SHA1")); + } else { + StringBuilder sb = new StringBuilder(givenAlg); + // case-insensitive check + if (givenAlg.regionMatches(true, 0, "SHA", 0, 3)) { + givenAlg = sb.insert(3, "-").toString(); + return stdAlg.equalsIgnoreCase(givenAlg); + } else { + throw new ProviderException("Unsupported digest algorithm " + + givenAlg); + } + } + } + } + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // name of the key algorithm, currently just RSA + private static final String KEY_ALGO = "RSA"; + + // mechanism id + private final CK_MECHANISM mechanism; + + // type, one of T_* below + private final int type; + + // key instance used, if init*() was called + private P11Key p11Key = null; + + // PSS parameters and the flag controlling its access + private PSSParameterSpec sigParams = null; + private boolean isActive = false; + + // message digest alg, if implied by the algorithm name + private final String mdAlg; + + // message digest, if we do the digesting ourselves + private MessageDigest md = null; + + // associated session, if any + private Session session; + + // mode, one of M_* below + private int mode; + + // flag indicating whether an operation is initialized + private boolean initialized = false; + + // buffer, for update(byte) + private final byte[] buffer = new byte[1]; + + // total number of bytes processed in current operation + private int bytesProcessed = 0; + + // constant for signing mode + private final static int M_SIGN = 1; + // constant for verification mode + private final static int M_VERIFY = 2; + + // constant for type digesting, we do the hashing ourselves + private final static int T_DIGEST = 1; + // constant for type update, token does everything + private final static int T_UPDATE = 2; + + P11PSSSignature(Token token, String algorithm, long mechId) + throws NoSuchAlgorithmException, PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = new CK_MECHANISM(mechId); + int idx = algorithm.indexOf("with"); + this.mdAlg = (idx == -1? null : algorithm.substring(0, idx)); + switch ((int)mechId) { + case (int)CKM_SHA1_RSA_PKCS_PSS: + case (int)CKM_SHA224_RSA_PKCS_PSS: + case (int)CKM_SHA256_RSA_PKCS_PSS: + case (int)CKM_SHA384_RSA_PKCS_PSS: + case (int)CKM_SHA512_RSA_PKCS_PSS: + type = T_UPDATE; + break; + case (int)CKM_RSA_PKCS_PSS: + type = T_DIGEST; + break; + default: + throw new ProviderException("Unsupported mechanism: " + mechId); + } + this.md = null; + } + + private void ensureInitialized() throws SignatureException { + token.ensureValid(); + if (this.p11Key == null) { + throw new SignatureException("Missing key"); + } + if (this.sigParams == null) { + if (this.mdAlg == null) { + // PSS Parameters are required for signature verification + throw new SignatureException + ("Parameters required for RSASSA-PSS signature"); + } else { + int saltLen = DIGEST_LENGTHS.get(this.mdAlg).intValue(); + // generate default params for both sign and verify? + this.sigParams = new PSSParameterSpec(this.mdAlg, + "MGF1", new MGF1ParameterSpec(this.mdAlg), + saltLen, PSSParameterSpec.TRAILER_FIELD_BC); + this.mechanism.setParameter(new CK_RSA_PKCS_PSS_PARAMS( + this.mdAlg, "MGF1", this.mdAlg, + DIGEST_LENGTHS.get(this.mdAlg).intValue())); + } + } + + if (initialized == false) { + initialize(); + } + } + + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + + try { + if (session == null) { + return; + } + + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + mechanism.freeHandle(); + session = token.releaseSession(session); + isActive = false; + } + } + + private void cancelOperation() { + token.ensureValid(); + if (DEBUG) System.out.print("Cancelling operation"); + + // cancel operation by finishing it; avoid killSession as some + // hardware vendors may require re-login + try { + if (mode == M_SIGN) { + if (type == T_UPDATE) { + if (DEBUG) System.out.println(" by C_SignFinal"); + token.p11.C_SignFinal(session.id(), 0); + } else { + byte[] digest = + (md == null? new byte[0] : md.digest()); + if (DEBUG) System.out.println(" by C_Sign"); + token.p11.C_Sign(session.id(), digest); + } + } else { // M_VERIFY + byte[] signature = + new byte[(p11Key.length() + 7) >> 3]; + if (type == T_UPDATE) { + if (DEBUG) System.out.println(" by C_VerifyFinal"); + token.p11.C_VerifyFinal(session.id(), signature); + } else { + byte[] digest = + (md == null? new byte[0] : md.digest()); + if (DEBUG) System.out.println(" by C_Verify"); + token.p11.C_Verify(session.id(), digest, signature); + } + } + } catch (PKCS11Exception e) { + if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { + // Cancel Operation may be invoked after an error on a PKCS#11 + // call. If the operation inside the token was already cancelled, + // do not fail here. This is part of a defensive mechanism for + // PKCS#11 libraries that do not strictly follow the standard. + return; + } + if (mode == M_SIGN) { + throw new ProviderException("cancel failed", e); + } + // ignore failure for verification + } + } + + // assumes current state is initialized == false + private void initialize() { + if (DEBUG) System.out.println("Initializing"); + + if (p11Key == null) { + throw new ProviderException( + "No Key found, call initSign/initVerify first"); + } + + long keyID = p11Key.getKeyID(); + try { + if (session == null) { + session = token.getOpSession(); + } + if (mode == M_SIGN) { + token.p11.C_SignInit(session.id(), mechanism, keyID); + } else { + token.p11.C_VerifyInit(session.id(), mechanism, keyID); + } + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw new ProviderException("Initialization failed", e); + } + if (bytesProcessed != 0) { + bytesProcessed = 0; + if (md != null) { + md.reset(); + } + } + initialized = true; + isActive = false; + if (DEBUG) System.out.println("Initialized"); + } + + private void checkKeySize(Key key) throws InvalidKeyException { + if (DEBUG) System.out.print("Checking Key"); + + if (!key.getAlgorithm().equals(KEY_ALGO)) { + throw new InvalidKeyException("Only " + KEY_ALGO + + " keys are supported"); + } + + CK_MECHANISM_INFO mechInfo = null; + try { + mechInfo = token.getMechanismInfo(mechanism.mechanism); + } catch (PKCS11Exception e) { + // should not happen, ignore for now + if (DEBUG) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + } + } + + int keySize = 0; // in bytes + if (mechInfo != null) { + if (key instanceof P11Key) { + keySize = (((P11Key) key).length() + 7) >> 3; + } else if (key instanceof RSAKey) { + keySize = ((RSAKey) key).getModulus().bitLength() >> 3; + } else { + throw new InvalidKeyException("Unrecognized key type " + key); + } + // check against available native info which are in bits + if ((mechInfo.iMinKeySize != 0) && + (keySize < (mechInfo.iMinKeySize >> 3))) { + throw new InvalidKeyException(KEY_ALGO + + " key must be at least " + mechInfo.iMinKeySize + " bits"); + } + if ((mechInfo.iMaxKeySize != Integer.MAX_VALUE) && + (keySize > (mechInfo.iMaxKeySize >> 3))) { + throw new InvalidKeyException(KEY_ALGO + + " key must be at most " + mechInfo.iMaxKeySize + " bits"); + } + } + if (this.sigParams != null) { + String digestAlg = this.sigParams.getDigestAlgorithm(); + int sLen = this.sigParams.getSaltLength(); + int hLen = DIGEST_LENGTHS.get(digestAlg).intValue(); + int minKeyLen = Math.addExact(Math.addExact(sLen, hLen), 2); + + if (keySize < minKeyLen) { + throw new InvalidKeyException + ("Key is too short for current params, need min " + minKeyLen); + } + } + } + + private void setSigParams(AlgorithmParameterSpec p) + throws InvalidAlgorithmParameterException { + if (p == null) { + throw new InvalidAlgorithmParameterException("PSS Parameter required"); + } + if (!(p instanceof PSSParameterSpec)) { + throw new InvalidAlgorithmParameterException + ("Only PSSParameterSpec is supported"); + } + // no need to validate again if same as current signature parameters + PSSParameterSpec params = (PSSParameterSpec) p; + if (params == this.sigParams) return; + + String digestAlgorithm = params.getDigestAlgorithm(); + if (this.mdAlg != null && !isDigestEqual(digestAlgorithm, this.mdAlg)) { + throw new InvalidAlgorithmParameterException + ("Digest algorithm in Signature parameters must be " + + this.mdAlg); + } + Integer digestLen = DIGEST_LENGTHS.get(digestAlgorithm); + if (digestLen == null) { + throw new InvalidAlgorithmParameterException + ("Unsupported digest algorithm in Signature parameters: " + + digestAlgorithm); + } + if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) { + throw new InvalidAlgorithmParameterException("Only supports MGF1"); + } + if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) { + throw new InvalidAlgorithmParameterException + ("Only supports TrailerFieldBC(1)"); + } + int saltLen = params.getSaltLength(); + if (this.p11Key != null) { + int maxSaltLen = ((this.p11Key.length() + 7) >> 3) - digestLen.intValue() - 2; + + if (DEBUG) { + System.out.println("Max saltLen = " + maxSaltLen); + System.out.println("Curr saltLen = " + saltLen); + } + if (maxSaltLen < 0 || saltLen > maxSaltLen) { + throw new InvalidAlgorithmParameterException("Invalid with current key size"); + } + } else { + if (DEBUG) System.out.println("No key available for validating saltLen"); + } + + // validated, now try to store the parameter internally + try { + this.mechanism.setParameter( + new CK_RSA_PKCS_PSS_PARAMS(digestAlgorithm, "MGF1", + digestAlgorithm, saltLen)); + this.sigParams = params; + } catch (IllegalArgumentException iae) { + throw new InvalidAlgorithmParameterException(iae); + } + } + + // see JCA spec + @Override + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException { + + if (publicKey == null) { + throw new InvalidKeyException("Key must not be null"); + } + + // Need to check key length whenever a new key is set + if (publicKey != p11Key) { + checkKeySize(publicKey); + } + + reset(true); + mode = M_VERIFY; + p11Key = P11KeyFactory.convertKey(token, publicKey, KEY_ALGO); + + // For PSS, defer PKCS11 initialization calls to update/doFinal as it + // needs both key and params + } + + // see JCA spec + @Override + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException { + + if (privateKey == null) { + throw new InvalidKeyException("Key must not be null"); + } + + // Need to check RSA key length whenever a new key is set + if (privateKey != p11Key) { + checkKeySize(privateKey); + } + + reset(true); + mode = M_SIGN; + p11Key = P11KeyFactory.convertKey(token, privateKey, KEY_ALGO); + + // For PSS, defer PKCS11 initialization calls to update/doFinal as it + // needs both key and params + } + + // see JCA spec + @Override + protected void engineUpdate(byte b) throws SignatureException { + ensureInitialized(); + isActive = true; + buffer[0] = b; + engineUpdate(buffer, 0, 1); + } + + // see JCA spec + @Override + protected void engineUpdate(byte[] b, int ofs, int len) + throws SignatureException { + ensureInitialized(); + if (len == 0) { + return; + } + // check for overflow + if (len + bytesProcessed < 0) { + throw new ProviderException("Processed bytes limits exceeded."); + } + isActive = true; + switch (type) { + case T_UPDATE: + try { + if (mode == M_SIGN) { + if (DEBUG) System.out.println(this + ": Calling C_SignUpdate"); + token.p11.C_SignUpdate(session.id(), 0, b, ofs, len); + } else { + if (DEBUG) System.out.println(this + ": Calling C_VerfifyUpdate"); + token.p11.C_VerifyUpdate(session.id(), 0, b, ofs, len); + } + bytesProcessed += len; + } catch (PKCS11Exception e) { + reset(false); + throw new ProviderException(e); + } + break; + case T_DIGEST: + // should not happen as this should be covered by earlier checks + if (md == null) { + throw new ProviderException("PSS Parameters required"); + } + md.update(b, ofs, len); + bytesProcessed += len; + break; + default: + throw new ProviderException("Internal error"); + } + } + + // see JCA spec + @Override + protected void engineUpdate(ByteBuffer byteBuffer) { + try { + ensureInitialized(); + } catch (SignatureException se) { + throw new ProviderException(se); + } + int len = byteBuffer.remaining(); + if (len <= 0) { + return; + } + isActive = true; + switch (type) { + case T_UPDATE: + if (byteBuffer instanceof DirectBuffer == false) { + // cannot do better than default impl + super.engineUpdate(byteBuffer); + return; + } + long addr = ((DirectBuffer)byteBuffer).address(); + int ofs = byteBuffer.position(); + try { + if (mode == M_SIGN) { + if (DEBUG) System.out.println(this + ": Calling C_SignUpdate"); + token.p11.C_SignUpdate + (session.id(), addr + ofs, null, 0, len); + } else { + if (DEBUG) System.out.println(this + ": Calling C_VerifyUpdate"); + token.p11.C_VerifyUpdate + (session.id(), addr + ofs, null, 0, len); + } + bytesProcessed += len; + byteBuffer.position(ofs + len); + } catch (PKCS11Exception e) { + reset(false); + throw new ProviderException("Update failed", e); + } + break; + case T_DIGEST: + // should not happen as this should be covered by earlier checks + if (md == null) { + throw new ProviderException("PSS Parameters required"); + } + md.update(byteBuffer); + bytesProcessed += len; + break; + default: + reset(false); + throw new ProviderException("Internal error"); + } + } + + // see JCA spec + @Override + protected byte[] engineSign() throws SignatureException { + ensureInitialized(); + boolean doCancel = true; + if (DEBUG) System.out.print("Generating signature"); + try { + byte[] signature; + if (type == T_UPDATE) { + if (DEBUG) System.out.println(" by C_SignFinal"); + signature = token.p11.C_SignFinal(session.id(), 0); + } else { + if (md == null) { + throw new ProviderException("PSS Parameters required"); + } + byte[] digest = md.digest(); + if (DEBUG) System.out.println(" by C_Sign"); + signature = token.p11.C_Sign(session.id(), digest); + } + doCancel = false; + return signature; + } catch (PKCS11Exception pe) { + // As per the PKCS#11 standard, C_Sign and C_SignFinal may only + // keep the operation active on CKR_BUFFER_TOO_SMALL errors or + // successful calls to determine the output length. However, + // these cases are handled at OpenJDK's libj2pkcs11 native + // library. Thus, doCancel can safely be 'false' here. + doCancel = false; + throw new ProviderException(pe); + } catch (ProviderException e) { + throw e; + } finally { + reset(doCancel); + } + } + + // see JCA spec + @Override + protected boolean engineVerify(byte[] signature) throws SignatureException { + ensureInitialized(); + boolean doCancel = true; + if (DEBUG) System.out.print("Verifying signature"); + try { + if (type == T_UPDATE) { + if (DEBUG) System.out.println(" by C_VerifyFinal"); + token.p11.C_VerifyFinal(session.id(), signature); + } else { + if (md == null) { + throw new ProviderException("PSS Parameters required"); + } + byte[] digest = md.digest(); + if (DEBUG) System.out.println(" by C_Verify"); + token.p11.C_Verify(session.id(), digest, signature); + } + doCancel = false; + return true; + } catch (PKCS11Exception pe) { + doCancel = false; + long errorCode = pe.getErrorCode(); + if (errorCode == CKR_SIGNATURE_INVALID) { + return false; + } + if (errorCode == CKR_SIGNATURE_LEN_RANGE) { + // return false rather than throwing an exception + return false; + } + // ECF bug? + if (errorCode == CKR_DATA_LEN_RANGE) { + return false; + } + throw new ProviderException(pe); + } catch (ProviderException e) { + throw e; + } finally { + reset(doCancel); + } + } + + // see JCA spec + @SuppressWarnings("deprecation") + @Override + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new UnsupportedOperationException("setParameter() not supported"); + } + + // see JCA spec + @Override + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + // disallow changing parameters when update has been called + if (isActive) { + throw new ProviderException + ("Cannot set parameters during operations"); + } + setSigParams(params); + if (type == T_DIGEST) { + try { + this.md = MessageDigest.getInstance(sigParams.getDigestAlgorithm()); + } catch (NoSuchAlgorithmException nsae) { + throw new InvalidAlgorithmParameterException(nsae); + } + } + } + + // see JCA spec + @SuppressWarnings("deprecation") + @Override + protected Object engineGetParameter(String param) + throws InvalidParameterException { + throw new UnsupportedOperationException("getParameter() not supported"); + } + + // see JCA spec + @Override + protected AlgorithmParameters engineGetParameters() { + if (this.sigParams != null) { + try { + AlgorithmParameters ap = AlgorithmParameters.getInstance("RSASSA-PSS"); + ap.init(this.sigParams); + return ap; + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + } + return null; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11RSACipher.java b/src/main/java/com/sunyard/security/pkcs11/P11RSACipher.java new file mode 100644 index 0000000..9f34c31 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11RSACipher.java @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.*; + +import java.util.Locale; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; + +/** + * RSA Cipher implementation class. We currently only support + * PKCS#1 v1.5 padding on top of CKM_RSA_PKCS. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11RSACipher extends CipherSpi { + + // minimum length of PKCS#1 v1.5 padding + private final static int PKCS1_MIN_PADDING_LENGTH = 11; + + // constant byte[] of length 0 + private final static byte[] B0 = new byte[0]; + + // mode constant for public key encryption + private final static int MODE_ENCRYPT = 1; + // mode constant for private key decryption + private final static int MODE_DECRYPT = 2; + // mode constant for private key encryption (signing) + private final static int MODE_SIGN = 3; + // mode constant for public key decryption (verifying) + private final static int MODE_VERIFY = 4; + + // padding type constant for NoPadding + private final static int PAD_NONE = 1; + // padding type constant for PKCS1Padding + private final static int PAD_PKCS1 = 2; + + // token instance + private final Token token; + + // algorithm name (always "RSA") + private final String algorithm; + + // mechanism id + private final long mechanism; + + // associated session, if any + private Session session; + + // mode, one of MODE_* above + private int mode; + + // padding, one of PAD_* above + private int padType; + + private byte[] buffer; + private int bufOfs; + + // key, if init() was called + private P11Key p11Key; + + // flag indicating whether an operation is initialized + private boolean initialized; + + // maximum input data size allowed + // for decryption, this is the length of the key + // for encryption, length of the key minus minimum padding length + private int maxInputSize; + + // maximum output size. this is the length of the key + private int outputSize; + + // cipher parameter for TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; + + // the source of randomness + private SecureRandom random; + + P11RSACipher(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = "RSA"; + this.mechanism = mechanism; + } + + // modes do not make sense for RSA, but allow ECB + // see JCE spec + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + if (mode.equalsIgnoreCase("ECB") == false) { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + } + + protected void engineSetPadding(String padding) + throws NoSuchPaddingException { + String lowerPadding = padding.toLowerCase(Locale.ENGLISH); + if (lowerPadding.equals("pkcs1padding")) { + padType = PAD_PKCS1; + } else if (lowerPadding.equals("nopadding")) { + padType = PAD_NONE; + } else { + throw new NoSuchPaddingException("Unsupported padding " + padding); + } + } + + // return 0 as block size, we are not a block cipher + // see JCE spec + protected int engineGetBlockSize() { + return 0; + } + + // return the output size + // see JCE spec + protected int engineGetOutputSize(int inputLen) { + return outputSize; + } + + // no IV, return null + // see JCE spec + protected byte[] engineGetIV() { + return null; + } + + // no parameters, return null + // see JCE spec + protected AlgorithmParameters engineGetParameters() { + return null; + } + + // see JCE spec + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException { + implInit(opmode, key); + } + + // see JCE spec + protected void engineInit(int opmode, Key key, + AlgorithmParameterSpec params, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (params != null) { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + spec = params; + this.random = random; // for TLS RSA premaster secret + } + implInit(opmode, key); + } + + // see JCE spec + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + implInit(opmode, key); + } + + private void implInit(int opmode, Key key) throws InvalidKeyException { + reset(true); + p11Key = P11KeyFactory.convertKey(token, key, algorithm); + boolean encrypt; + if (opmode == Cipher.ENCRYPT_MODE) { + encrypt = true; + } else if (opmode == Cipher.DECRYPT_MODE) { + encrypt = false; + } else if (opmode == Cipher.WRAP_MODE) { + if (p11Key.isPublic() == false) { + throw new InvalidKeyException + ("Wrap has to be used with public keys"); + } + // No further setup needed for C_Wrap(). We'll initialize later if + // we can't use C_Wrap(). + return; + } else if (opmode == Cipher.UNWRAP_MODE) { + if (p11Key.isPrivate() == false) { + throw new InvalidKeyException + ("Unwrap has to be used with private keys"); + } + // No further setup needed for C_Unwrap(). We'll initialize later + // if we can't use C_Unwrap(). + return; + } else { + throw new InvalidKeyException("Unsupported mode: " + opmode); + } + if (p11Key.isPublic()) { + mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; + } else if (p11Key.isPrivate()) { + mode = encrypt ? MODE_SIGN : MODE_DECRYPT; + } else { + throw new InvalidKeyException("Unknown key type: " + p11Key); + } + int n = (p11Key.length() + 7) >> 3; + outputSize = n; + buffer = new byte[n]; + maxInputSize = ((padType == PAD_PKCS1 && encrypt) ? + (n - PKCS1_MIN_PADDING_LENGTH) : n); + try { + initialize(); + } catch (PKCS11Exception e) { + throw new InvalidKeyException("init() failed", e); + } + } + + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + + try { + if (session == null) { + return; + } + + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + } + } + + // should only called by reset as this method does not update other + // state variables such as "initialized" + private void cancelOperation() { + token.ensureValid(); + // cancel operation by finishing it; avoid killSession as some + // hardware vendors may require re-login + try { + PKCS11 p11 = token.p11; + int inLen = maxInputSize; + int outLen = buffer.length; + long sessId = session.id(); + switch (mode) { + case MODE_ENCRYPT: + p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen); + break; + case MODE_DECRYPT: + p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen); + break; + case MODE_SIGN: + byte[] tmpBuffer = new byte[maxInputSize]; + p11.C_Sign(sessId, tmpBuffer); + break; + case MODE_VERIFY: + p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer, + 0, outLen); + break; + default: + throw new ProviderException("internal error"); + } + } catch (PKCS11Exception e) { + // XXX ensure this always works, ignore error + } + } + + private void ensureInitialized() throws PKCS11Exception { + token.ensureValid(); + if (!initialized) { + initialize(); + } + } + + private void initialize() throws PKCS11Exception { + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without " + + "calling engineInit first"); + } + long keyID = p11Key.getKeyID(); + try { + if (session == null) { + session = token.getOpSession(); + } + PKCS11 p11 = token.p11; + CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism); + switch (mode) { + case MODE_ENCRYPT: + p11.C_EncryptInit(session.id(), ckMechanism, keyID); + break; + case MODE_DECRYPT: + p11.C_DecryptInit(session.id(), ckMechanism, keyID); + break; + case MODE_SIGN: + p11.C_SignInit(session.id(), ckMechanism, keyID); + break; + case MODE_VERIFY: + p11.C_VerifyRecoverInit(session.id(), ckMechanism, keyID); + break; + default: + throw new AssertionError("internal error"); + } + bufOfs = 0; + initialized = true; + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw e; + } + } + + private void implUpdate(byte[] in, int inOfs, int inLen) { + try { + ensureInitialized(); + } catch (PKCS11Exception e) { + throw new ProviderException("update() failed", e); + } + if ((inLen == 0) || (in == null)) { + return; + } + if (bufOfs + inLen > maxInputSize) { + bufOfs = maxInputSize + 1; + return; + } + System.arraycopy(in, inOfs, buffer, bufOfs, inLen); + bufOfs += inLen; + } + + private int implDoFinal(byte[] out, int outOfs, int outLen) + throws BadPaddingException, IllegalBlockSizeException { + if (bufOfs > maxInputSize) { + reset(true); + throw new IllegalBlockSizeException("Data must not be longer " + + "than " + maxInputSize + " bytes"); + } + try { + ensureInitialized(); + PKCS11 p11 = token.p11; + int n; + switch (mode) { + case MODE_ENCRYPT: + n = p11.C_Encrypt + (session.id(), 0, buffer, 0, bufOfs, 0, out, outOfs, outLen); + break; + case MODE_DECRYPT: + n = p11.C_Decrypt + (session.id(), 0, buffer, 0, bufOfs, 0, out, outOfs, outLen); + break; + case MODE_SIGN: + byte[] tmpBuffer = new byte[bufOfs]; + System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs); + tmpBuffer = p11.C_Sign(session.id(), tmpBuffer); + if (tmpBuffer.length > outLen) { + throw new BadPaddingException( + "Output buffer (" + outLen + ") is too small to " + + "hold the produced data (" + tmpBuffer.length + ")"); + } + System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length); + n = tmpBuffer.length; + break; + case MODE_VERIFY: + n = p11.C_VerifyRecover + (session.id(), buffer, 0, bufOfs, out, outOfs, outLen); + break; + default: + throw new ProviderException("internal error"); + } + return n; + } catch (PKCS11Exception e) { + throw (BadPaddingException)new BadPaddingException + ("doFinal() failed").initCause(e); + } finally { + reset(false); + } + } + + // see JCE spec + protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { + implUpdate(in, inOfs, inLen); + return B0; + } + + // see JCE spec + protected int engineUpdate(byte[] in, int inOfs, int inLen, + byte[] out, int outOfs) throws ShortBufferException { + implUpdate(in, inOfs, inLen); + return 0; + } + + // see JCE spec + protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) + throws IllegalBlockSizeException, BadPaddingException { + implUpdate(in, inOfs, inLen); + int n = implDoFinal(buffer, 0, buffer.length); + byte[] out = new byte[n]; + System.arraycopy(buffer, 0, out, 0, n); + return out; + } + + // see JCE spec + protected int engineDoFinal(byte[] in, int inOfs, int inLen, + byte[] out, int outOfs) throws ShortBufferException, + IllegalBlockSizeException, BadPaddingException { + implUpdate(in, inOfs, inLen); + return implDoFinal(out, outOfs, out.length - outOfs); + } + + private byte[] doFinal() throws BadPaddingException, + IllegalBlockSizeException { + byte[] t = new byte[2048]; + int n = implDoFinal(t, 0, t.length); + byte[] out = new byte[n]; + System.arraycopy(t, 0, out, 0, n); + return out; + } + + // see JCE spec + protected byte[] engineWrap(Key key) throws InvalidKeyException, + IllegalBlockSizeException { + String keyAlg = key.getAlgorithm(); + P11Key sKey = null; + try { + // The conversion may fail, e.g. trying to wrap an AES key on + // a token that does not support AES, or when the key size is + // not within the range supported by the token. + sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg); + } catch (InvalidKeyException ike) { + byte[] toBeWrappedKey = key.getEncoded(); + if (toBeWrappedKey == null) { + throw new InvalidKeyException + ("wrap() failed, no encoding available", ike); + } + // Directly encrypt the key encoding when key conversion failed + implInit(Cipher.ENCRYPT_MODE, p11Key); + implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length); + try { + return doFinal(); + } catch (BadPaddingException bpe) { + // should not occur + throw new InvalidKeyException("wrap() failed", bpe); + } finally { + // Restore original mode + implInit(Cipher.WRAP_MODE, p11Key); + } + } + Session s = null; + long p11KeyID = p11Key.getKeyID(); + long sKeyID = sKey.getKeyID(); + try { + s = token.getOpSession(); + return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism), + p11KeyID, sKeyID); + } catch (PKCS11Exception e) { + throw new InvalidKeyException("wrap() failed", e); + } finally { + p11Key.releaseKeyID(); + sKey.releaseKeyID(); + token.releaseSession(s); + } + } + + // see JCE spec + protected Key engineUnwrap(byte[] wrappedKey, String algorithm, + int type) throws InvalidKeyException, NoSuchAlgorithmException { + + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + + // Should C_Unwrap be preferred for non-TLS RSA premaster secret? + if (token.supportsRawSecretKeyImport()) { + // XXX implement unwrap using C_Unwrap() for all keys + implInit(Cipher.DECRYPT_MODE, p11Key); + try { + if (wrappedKey.length > maxInputSize) { + throw new InvalidKeyException("Key is too long for unwrapping"); + } + + byte[] encoded = null; + implUpdate(wrappedKey, 0, wrappedKey.length); + try { + encoded = doFinal(); + } catch (BadPaddingException e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } + } catch (IllegalBlockSizeException e) { + // should not occur, handled with length check above + throw new InvalidKeyException("Unwrapping failed", e); + } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + TlsRsaPremasterSecretParameterSpec psps = + (TlsRsaPremasterSecretParameterSpec)spec; + encoded = KeyUtil.checkTlsPreMasterSecretKey( + psps.getClientVersion(), psps.getServerVersion(), + random, encoded, (failover != null)); + } + + return ConstructKeys.constructKey(encoded, algorithm, type); + } finally { + // Restore original mode + implInit(Cipher.UNWRAP_MODE, p11Key); + } + } else { + Session s = null; + SecretKey secretKey = null; + long p11KeyID = p11Key.getKeyID(); + try { + try { + s = token.getObjSession(); + long keyType = CKK_GENERIC_SECRET; + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + attributes = token.getAttributes( + O_IMPORT, CKO_SECRET_KEY, keyType, attributes); + + long keyID = token.p11.C_UnwrapKey(s.id(), + new CK_MECHANISM(mechanism), p11KeyID, + wrappedKey, attributes); + secretKey = P11Key.secretKey(s, keyID, + algorithm, 48 << 3, attributes); + } catch (PKCS11Exception e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("unwrap() failed", e); + } + } + + if (isTlsRsaPremasterSecret) { + TlsRsaPremasterSecretParameterSpec psps = + (TlsRsaPremasterSecretParameterSpec)spec; + + // Please use the tricky failover as the parameter so that + // smart compiler won't dispose the unused variable. + secretKey = polishPreMasterSecretKey(token, s, + failover, secretKey, + psps.getClientVersion(), psps.getServerVersion()); + } + + return secretKey; + } finally { + p11Key.releaseKeyID(); + token.releaseSession(s); + } + } + } + + // see JCE spec + protected int engineGetKeySize(Key key) throws InvalidKeyException { + int n = P11KeyFactory.convertKey(token, key, algorithm).length(); + return n; + } + + private static SecretKey polishPreMasterSecretKey( + Token token, Session session, + Exception failover, SecretKey unwrappedKey, + int clientVersion, int serverVersion) { + + SecretKey newKey; + CK_VERSION version = new CK_VERSION( + (clientVersion >>> 8) & 0xFF, clientVersion & 0xFF); + try { + CK_ATTRIBUTE[] attributes = token.getAttributes( + O_GENERATE, CKO_SECRET_KEY, + CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_GenerateKey(session.id(), + new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version), + attributes); + newKey = P11Key.secretKey(session, + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + } catch (PKCS11Exception e) { + throw new ProviderException( + "Could not generate premaster secret", e); + } + + return (failover == null) ? unwrappedKey : newKey; + } + +} + +final class ConstructKeys { + /** + * Construct a public key from its encoding. + * + * @param encodedKey the encoding of a public key. + * + * @param encodedKeyAlgorithm the algorithm the encodedKey is for. + * + * @return a public key constructed from the encodedKey. + */ + private static final PublicKey constructPublicKey(byte[] encodedKey, + String encodedKeyAlgorithm) + throws InvalidKeyException, NoSuchAlgorithmException { + try { + KeyFactory keyFactory = + KeyFactory.getInstance(encodedKeyAlgorithm); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); + return keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException nsae) { + throw new NoSuchAlgorithmException("No installed providers " + + "can create keys for the " + + encodedKeyAlgorithm + + "algorithm", nsae); + } catch (InvalidKeySpecException ike) { + throw new InvalidKeyException("Cannot construct public key", ike); + } + } + + /** + * Construct a private key from its encoding. + * + * @param encodedKey the encoding of a private key. + * + * @param encodedKeyAlgorithm the algorithm the wrapped key is for. + * + * @return a private key constructed from the encodedKey. + */ + private static final PrivateKey constructPrivateKey(byte[] encodedKey, + String encodedKeyAlgorithm) throws InvalidKeyException, + NoSuchAlgorithmException { + try { + KeyFactory keyFactory = + KeyFactory.getInstance(encodedKeyAlgorithm); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); + return keyFactory.generatePrivate(keySpec); + } catch (NoSuchAlgorithmException nsae) { + throw new NoSuchAlgorithmException("No installed providers " + + "can create keys for the " + + encodedKeyAlgorithm + + "algorithm", nsae); + } catch (InvalidKeySpecException ike) { + throw new InvalidKeyException("Cannot construct private key", ike); + } + } + + /** + * Construct a secret key from its encoding. + * + * @param encodedKey the encoding of a secret key. + * + * @param encodedKeyAlgorithm the algorithm the secret key is for. + * + * @return a secret key constructed from the encodedKey. + */ + private static final SecretKey constructSecretKey(byte[] encodedKey, + String encodedKeyAlgorithm) { + return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); + } + + static final Key constructKey(byte[] encoding, String keyAlgorithm, + int keyType) throws InvalidKeyException, NoSuchAlgorithmException { + switch (keyType) { + case Cipher.SECRET_KEY: + return constructSecretKey(encoding, keyAlgorithm); + case Cipher.PRIVATE_KEY: + return constructPrivateKey(encoding, keyAlgorithm); + case Cipher.PUBLIC_KEY: + return constructPublicKey(encoding, keyAlgorithm); + default: + throw new InvalidKeyException("Unknown keytype " + keyType); + } + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11RSAKeyFactory.java b/src/main/java/com/sunyard/security/pkcs11/P11RSAKeyFactory.java new file mode 100644 index 0000000..593b065 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11RSAKeyFactory.java @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; + +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; + +import sun.security.rsa.RSAPublicKeyImpl; +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +import sun.security.rsa.RSAKeyFactory; + +/** + * RSA KeyFactory implementation. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11RSAKeyFactory extends P11KeyFactory { + + P11RSAKeyFactory(Token token, String algorithm) { + super(token, algorithm); + } + + PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { + try { + if (key instanceof RSAPublicKey) { + RSAPublicKey rsaKey = (RSAPublicKey)key; + return generatePublic( + rsaKey.getModulus(), + rsaKey.getPublicExponent() + ); + } else if ("X.509".equals(key.getFormat())) { + // let SunRsaSign provider parse for us, then recurse + byte[] encoded = key.getEncoded(); + key = RSAPublicKeyImpl.newKey(encoded); + return implTranslatePublicKey(key); + } else { + throw new InvalidKeyException("PublicKey must be instance " + + "of RSAPublicKey or have X.509 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create RSA public key", e); + } + } + + PrivateKey implTranslatePrivateKey(PrivateKey key) + throws InvalidKeyException { + try { + if (key instanceof RSAPrivateCrtKey) { + RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key; + return generatePrivate( + rsaKey.getModulus(), + rsaKey.getPublicExponent(), + rsaKey.getPrivateExponent(), + rsaKey.getPrimeP(), + rsaKey.getPrimeQ(), + rsaKey.getPrimeExponentP(), + rsaKey.getPrimeExponentQ(), + rsaKey.getCrtCoefficient() + ); + } else if (key instanceof RSAPrivateKey) { + RSAPrivateKey rsaKey = (RSAPrivateKey)key; + return generatePrivate( + rsaKey.getModulus(), + rsaKey.getPrivateExponent() + ); + } else if ("PKCS#8".equals(key.getFormat())) { + // let SunRsaSign provider parse for us, then recurse + byte[] encoded = key.getEncoded(); + key = sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(encoded); + return implTranslatePrivateKey(key); + } else { + throw new InvalidKeyException("Private key must be instance " + + "of RSAPrivate(Crt)Key or have PKCS#8 encoding"); + } + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create RSA private key", e); + } + } + + // see JCA spec + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof X509EncodedKeySpec) { + try { + byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded(); + PublicKey key = RSAPublicKeyImpl.newKey(encoded); + return implTranslatePublicKey(key); + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException + ("Could not create RSA public key", e); + } + } + if (keySpec instanceof RSAPublicKeySpec == false) { + throw new InvalidKeySpecException("Only RSAPublicKeySpec and " + + "X509EncodedKeySpec supported for RSA public keys"); + } + try { + RSAPublicKeySpec rs = (RSAPublicKeySpec)keySpec; + return generatePublic( + rs.getModulus(), + rs.getPublicExponent() + ); + } catch (PKCS11Exception | InvalidKeyException e) { + throw new InvalidKeySpecException + ("Could not create RSA public key", e); + } + } + + // see JCA spec + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec instanceof PKCS8EncodedKeySpec) { + try { + byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); + PrivateKey key = + sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(encoded); + return implTranslatePrivateKey(key); + } catch (GeneralSecurityException e) { + throw new InvalidKeySpecException + ("Could not create RSA private key", e); + } + } + try { + if (keySpec instanceof RSAPrivateCrtKeySpec) { + RSAPrivateCrtKeySpec rs = (RSAPrivateCrtKeySpec)keySpec; + return generatePrivate( + rs.getModulus(), + rs.getPublicExponent(), + rs.getPrivateExponent(), + rs.getPrimeP(), + rs.getPrimeQ(), + rs.getPrimeExponentP(), + rs.getPrimeExponentQ(), + rs.getCrtCoefficient() + ); + } else if (keySpec instanceof RSAPrivateKeySpec) { + RSAPrivateKeySpec rs = (RSAPrivateKeySpec)keySpec; + return generatePrivate( + rs.getModulus(), + rs.getPrivateExponent() + ); + } else { + throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec " + + "and PKCS8EncodedKeySpec supported for RSA private keys"); + } + } catch (PKCS11Exception | InvalidKeyException e) { + throw new InvalidKeySpecException + ("Could not create RSA private key", e); + } + } + + private PublicKey generatePublic(BigInteger n, BigInteger e) + throws PKCS11Exception, InvalidKeyException { + RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), + new CK_ATTRIBUTE(CKA_MODULUS, n), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, e), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PUBLIC_KEY, CKK_RSA, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.publicKey + (session, keyID, "RSA", n.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + private PrivateKey generatePrivate(BigInteger n, BigInteger d) + throws PKCS11Exception, InvalidKeyException { + RSAKeyFactory.checkKeyLengths(n.bitLength(), null, -1, 64 * 1024); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), + new CK_ATTRIBUTE(CKA_MODULUS, n), + new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, d), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.privateKey + (session, keyID, "RSA", n.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + private PrivateKey generatePrivate(BigInteger n, BigInteger e, + BigInteger d, BigInteger p, BigInteger q, BigInteger pe, + BigInteger qe, BigInteger coeff) throws PKCS11Exception, + InvalidKeyException { + RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), + new CK_ATTRIBUTE(CKA_MODULUS, n), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, e), + new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, d), + new CK_ATTRIBUTE(CKA_PRIME_1, p), + new CK_ATTRIBUTE(CKA_PRIME_2, q), + new CK_ATTRIBUTE(CKA_EXPONENT_1, pe), + new CK_ATTRIBUTE(CKA_EXPONENT_2, qe), + new CK_ATTRIBUTE(CKA_COEFFICIENT, coeff), + }; + attributes = token.getAttributes + (O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attributes); + Session session = null; + try { + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + return P11Key.privateKey + (session, keyID, "RSA", n.bitLength(), attributes); + } finally { + token.releaseSession(session); + } + } + + T implGetPublicKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (keySpec.isAssignableFrom(RSAPublicKeySpec.class)) { + session[0] = token.getObjSession(); + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_MODULUS), + new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), + }; + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new RSAPublicKeySpec( + attributes[0].getBigInteger(), + attributes[1].getBigInteger() + ); + return keySpec.cast(spec); + } else { // X.509 handled in superclass + throw new InvalidKeySpecException("Only RSAPublicKeySpec and " + + "X509EncodedKeySpec supported for RSA public keys"); + } + } + + T implGetPrivateKeySpec(P11Key key, Class keySpec, + Session[] session) throws PKCS11Exception, InvalidKeySpecException { + if (key.sensitive || !key.extractable) { + throw new InvalidKeySpecException("Key is sensitive or not extractable"); + } + // If the key is both extractable and not sensitive, then when it was converted into a P11Key + // it was also converted into subclass of RSAPrivateKey which encapsulates all of the logic + // necessary to retrieve the attributes we need. This sub-class will also cache these attributes + // so that we do not need to query them more than once. + // Rather than rewrite this logic and make possibly slow calls to the token, we'll just use + // that existing logic. + if (keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class)) { + // All supported keyspecs (other than PKCS8EncodedKeySpec) descend from RSAPrivateCrtKeySpec + if (key instanceof RSAPrivateCrtKey) { + RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key; + return keySpec.cast(new RSAPrivateCrtKeySpec( + crtKey.getModulus(), + crtKey.getPublicExponent(), + crtKey.getPrivateExponent(), + crtKey.getPrimeP(), + crtKey.getPrimeQ(), + crtKey.getPrimeExponentP(), + crtKey.getPrimeExponentQ(), + crtKey.getCrtCoefficient(), + crtKey.getParams() + )); + } else { // RSAPrivateKey (non-CRT) + if (!keySpec.isAssignableFrom(RSAPrivateKeySpec.class)) { + throw new InvalidKeySpecException + ("RSAPrivateCrtKeySpec can only be used with CRT keys"); + } + + if (!(key instanceof RSAPrivateKey)) { + // We should never reach here as P11Key.privateKey() should always produce an instance + // of RSAPrivateKey when the RSA key is both extractable and non-sensitive. + throw new InvalidKeySpecException + ("Key must be an instance of RSAPrivateKeySpec. Was " + key.getClass()); + } + + // fall through to RSAPrivateKey (non-CRT) + RSAPrivateKey rsaKey = (RSAPrivateKey) key; + return keySpec.cast(new RSAPrivateKeySpec( + rsaKey.getModulus(), + rsaKey.getPrivateExponent(), + rsaKey.getParams() + )); + } + } else { // PKCS#8 handled in superclass + throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec " + + "and PKCS8EncodedKeySpec supported for RSA private keys"); + } + } + + KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { + return KeyFactory.getInstance("RSA", P11Util.getSunRsaSignProvider()); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11SecretKeyFactory.java b/src/main/java/com/sunyard/security/pkcs11/P11SecretKeyFactory.java new file mode 100644 index 0000000..758a3e1 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11SecretKeyFactory.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; + +import java.security.*; +import java.security.spec.*; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * SecretKeyFactory implementation class. This class currently supports + * DES, DESede, AES, ARCFOUR, and Blowfish. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11SecretKeyFactory extends SecretKeyFactorySpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + P11SecretKeyFactory(Token token, String algorithm) { + super(); + this.token = token; + this.algorithm = algorithm; + } + + private static final Map keyTypes; + + static { + keyTypes = new HashMap(); + addKeyType("RC4", CKK_RC4); + addKeyType("ARCFOUR", CKK_RC4); + addKeyType("DES", CKK_DES); + addKeyType("DESede", CKK_DES3); + addKeyType("AES", CKK_AES); + addKeyType("Blowfish", CKK_BLOWFISH); + + // we don't implement RC2 or IDEA, but we want to be able to generate + // keys for those SSL/TLS ciphersuites. + addKeyType("RC2", CKK_RC2); + addKeyType("IDEA", CKK_IDEA); + + addKeyType("TlsPremasterSecret", PCKK_TLSPREMASTER); + addKeyType("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER); + addKeyType("TlsMasterSecret", PCKK_TLSMASTER); + addKeyType("Generic", CKK_GENERIC_SECRET); + } + + private static void addKeyType(String name, long id) { + Long l = Long.valueOf(id); + keyTypes.put(name, l); + keyTypes.put(name.toUpperCase(Locale.ENGLISH), l); + } + + static long getKeyType(String algorithm) { + Long l = keyTypes.get(algorithm); + if (l == null) { + algorithm = algorithm.toUpperCase(Locale.ENGLISH); + l = keyTypes.get(algorithm); + if (l == null) { + if (algorithm.startsWith("HMAC")) { + return PCKK_HMAC; + } else if (algorithm.startsWith("SSLMAC")) { + return PCKK_SSLMAC; + } + } + } + return (l != null) ? l.longValue() : -1; + } + + /** + * Convert an arbitrary key of algorithm into a P11Key of provider. + * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init(). + */ + static P11Key convertKey(Token token, Key key, String algo) + throws InvalidKeyException { + return convertKey(token, key, algo, null); + } + + /** + * Convert an arbitrary key of algorithm w/ custom attributes into a + * P11Key of provider. + * Used in P11KeyStore.storeSkey. + */ + static P11Key convertKey(Token token, Key key, String algo, + CK_ATTRIBUTE[] extraAttrs) + throws InvalidKeyException { + token.ensureValid(); + if (key == null) { + throw new InvalidKeyException("Key must not be null"); + } + if (key instanceof SecretKey == false) { + throw new InvalidKeyException("Key must be a SecretKey"); + } + long algoType; + if (algo == null) { + algo = key.getAlgorithm(); + algoType = getKeyType(algo); + } else { + algoType = getKeyType(algo); + long keyAlgorithmType = getKeyType(key.getAlgorithm()); + if (algoType != keyAlgorithmType) { + if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) { + // ignore key algorithm for MACs + } else { + throw new InvalidKeyException + ("Key algorithm must be " + algo); + } + } + } + if (key instanceof P11Key) { + P11Key p11Key = (P11Key)key; + if (p11Key.token == token) { + if (extraAttrs != null) { + P11Key newP11Key = null; + Session session = null; + long p11KeyID = p11Key.getKeyID(); + try { + session = token.getObjSession(); + long newKeyID = token.p11.C_CopyObject(session.id(), + p11KeyID, extraAttrs); + newP11Key = (P11Key) (P11Key.secretKey(session, + newKeyID, p11Key.algorithm, p11Key.keyLength, + extraAttrs)); + } catch (PKCS11Exception p11e) { + throw new InvalidKeyException + ("Cannot duplicate the PKCS11 key", p11e); + } finally { + p11Key.releaseKeyID(); + token.releaseSession(session); + } + p11Key = newP11Key; + } + return p11Key; + } + } + P11Key p11Key = token.secretCache.get(key); + if (p11Key != null) { + return p11Key; + } + if ("RAW".equalsIgnoreCase(key.getFormat()) == false) { + throw new InvalidKeyException("Encoded format must be RAW"); + } + byte[] encoded = key.getEncoded(); + p11Key = createKey(token, encoded, algo, algoType, extraAttrs); + token.secretCache.put(key, p11Key); + return p11Key; + } + + static void fixDESParity(byte[] key, int offset) { + for (int i = 0; i < 8; i++) { + int b = key[offset] & 0xfe; + b |= (Integer.bitCount(b) & 1) ^ 1; + key[offset++] = (byte)b; + } + } + + private static P11Key createKey(Token token, byte[] encoded, + String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs) + throws InvalidKeyException { + int n = encoded.length << 3; + int keyLength = n; + try { + switch ((int)keyType) { + case (int)CKK_DES: + keyLength = + P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token); + fixDESParity(encoded, 0); + break; + case (int)CKK_DES3: + keyLength = + P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token); + fixDESParity(encoded, 0); + fixDESParity(encoded, 8); + if (keyLength == 112) { + keyType = CKK_DES2; + } else { + keyType = CKK_DES3; + fixDESParity(encoded, 16); + } + break; + case (int)CKK_AES: + keyLength = + P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token); + break; + case (int)CKK_RC4: + keyLength = + P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token); + break; + case (int)CKK_BLOWFISH: + keyLength = + P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n, + token); + break; + case (int)CKK_GENERIC_SECRET: + case (int)PCKK_TLSPREMASTER: + case (int)PCKK_TLSRSAPREMASTER: + case (int)PCKK_TLSMASTER: + keyType = CKK_GENERIC_SECRET; + break; + case (int)PCKK_SSLMAC: + case (int)PCKK_HMAC: + if (n == 0) { + throw new InvalidKeyException + ("MAC keys must not be empty"); + } + keyType = CKK_GENERIC_SECRET; + break; + default: + throw new InvalidKeyException("Unknown algorithm " + + algorithm); + } + } catch (InvalidAlgorithmParameterException iape) { + throw new InvalidKeyException("Invalid key for " + algorithm, + iape); + } catch (ProviderException pe) { + throw new InvalidKeyException("Could not create key", pe); + } + Session session = null; + try { + CK_ATTRIBUTE[] attributes; + if (extraAttrs != null) { + attributes = new CK_ATTRIBUTE[3 + extraAttrs.length]; + System.arraycopy(extraAttrs, 0, attributes, 3, + extraAttrs.length); + } else { + attributes = new CK_ATTRIBUTE[3]; + } + attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); + attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType); + attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded); + attributes = token.getAttributes + (O_IMPORT, CKO_SECRET_KEY, keyType, attributes); + session = token.getObjSession(); + long keyID = token.p11.C_CreateObject(session.id(), attributes); + P11Key p11Key = (P11Key)P11Key.secretKey + (session, keyID, algorithm, keyLength, attributes); + return p11Key; + } catch (PKCS11Exception e) { + throw new InvalidKeyException("Could not create key", e); + } finally { + token.releaseSession(session); + } + } + + // see JCE spec + protected SecretKey engineGenerateSecret(KeySpec keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if (keySpec == null) { + throw new InvalidKeySpecException("KeySpec must not be null"); + } + if (keySpec instanceof SecretKeySpec) { + try { + Key key = convertKey(token, (SecretKey)keySpec, algorithm); + return (SecretKey)key; + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } else if (algorithm.equalsIgnoreCase("DES")) { + if (keySpec instanceof DESKeySpec) { + byte[] keyBytes = ((DESKeySpec)keySpec).getKey(); + keySpec = new SecretKeySpec(keyBytes, "DES"); + return engineGenerateSecret(keySpec); + } + } else if (algorithm.equalsIgnoreCase("DESede")) { + if (keySpec instanceof DESedeKeySpec) { + byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey(); + keySpec = new SecretKeySpec(keyBytes, "DESede"); + return engineGenerateSecret(keySpec); + } + } + throw new InvalidKeySpecException + ("Unsupported spec: " + keySpec.getClass().getName()); + } + + private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException { + try { + key = engineTranslateKey(key); + if ("RAW".equalsIgnoreCase(key.getFormat()) == false) { + throw new InvalidKeySpecException + ("Could not obtain key bytes"); + } + byte[] k = key.getEncoded(); + return k; + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } + + // see JCE spec + protected KeySpec engineGetKeySpec(SecretKey key, Class keySpec) + throws InvalidKeySpecException { + token.ensureValid(); + if ((key == null) || (keySpec == null)) { + throw new InvalidKeySpecException + ("key and keySpec must not be null"); + } + if (keySpec.isAssignableFrom(SecretKeySpec.class)) { + return new SecretKeySpec(getKeyBytes(key), algorithm); + } else if (algorithm.equalsIgnoreCase("DES")) { + try { + if (keySpec.isAssignableFrom(DESKeySpec.class)) { + return new DESKeySpec(getKeyBytes(key)); + } + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } else if (algorithm.equalsIgnoreCase("DESede")) { + try { + if (keySpec.isAssignableFrom(DESedeKeySpec.class)) { + return new DESedeKeySpec(getKeyBytes(key)); + } + } catch (InvalidKeyException e) { + throw new InvalidKeySpecException(e); + } + } + throw new InvalidKeySpecException + ("Unsupported spec: " + keySpec.getName()); + } + + // see JCE spec + protected SecretKey engineTranslateKey(SecretKey key) + throws InvalidKeyException { + return (SecretKey)convertKey(token, key, algorithm); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11SecureRandom.java b/src/main/java/com/sunyard/security/pkcs11/P11SecureRandom.java new file mode 100644 index 0000000..d3d63bf --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11SecureRandom.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.*; +import java.security.*; +import com.sunyard.security.pkcs11.wrapper.*; + +/** + * SecureRandom implementation class. Some tokens support only + * C_GenerateRandom() and not C_SeedRandom(). In order not to lose an + * application specified seed, we create a SHA1PRNG that we mix with in that + * case. + * + * Note that since SecureRandom is thread safe, we only need one + * instance per PKCS#11 token instance. It is created on demand and cached + * in the SunPKCS11 class. + * + * Also note that we obtain the PKCS#11 session on demand, no need to tie one + * up. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11SecureRandom extends SecureRandomSpi { + + private static final long serialVersionUID = -8939510236124553291L; + + // token instance + private final Token token; + + // PRNG for mixing, non-null if active (i.e. setSeed() has been called) + private volatile SecureRandom mixRandom; + + // buffer, if mixing is used + private byte[] mixBuffer; + + // bytes remaining in mixBuffer, if mixing is used + private int buffered; + + /* + * we buffer data internally for efficiency but limit the lifetime + * to avoid using stale bits. + */ + // lifetime in ms, currently 100 ms (0.1 s) + private static final long MAX_IBUFFER_TIME = 100; + + // size of the internal buffer + private static final int IBUFFER_SIZE = 32; + + // internal buffer for the random bits + private transient byte[] iBuffer = new byte[IBUFFER_SIZE]; + + // number of bytes remain in iBuffer + private transient int ibuffered = 0; + + // time that data was read into iBuffer + private transient long lastRead = 0L; + + P11SecureRandom(Token token) { + this.token = token; + } + + // see JCA spec + @Override + protected synchronized void engineSetSeed(byte[] seed) { + if (seed == null) { + throw new NullPointerException("seed must not be null"); + } + Session session = null; + try { + session = token.getOpSession(); + token.p11.C_SeedRandom(session.id(), seed); + } catch (PKCS11Exception e) { + // cannot set seed + // let a SHA1PRNG use that seed instead + SecureRandom random = mixRandom; + if (random != null) { + random.setSeed(seed); + } else { + try { + mixBuffer = new byte[20]; + random = SecureRandom.getInstance("SHA1PRNG"); + // initialize object before assigning to class field + random.setSeed(seed); + mixRandom = random; + } catch (NoSuchAlgorithmException ee) { + throw new ProviderException(ee); + } + } + } finally { + token.releaseSession(session); + } + } + + // see JCA spec + @Override + protected void engineNextBytes(byte[] bytes) { + if ((bytes == null) || (bytes.length == 0)) { + return; + } + if (bytes.length <= IBUFFER_SIZE) { + int ofs = 0; + synchronized (iBuffer) { + while (ofs < bytes.length) { + long time = System.currentTimeMillis(); + // refill the internal buffer if empty or stale + if ((ibuffered == 0) || + !(time - lastRead < MAX_IBUFFER_TIME)) { + lastRead = time; + implNextBytes(iBuffer); + ibuffered = IBUFFER_SIZE; + } + // copy the buffered bytes into 'bytes' + while ((ofs < bytes.length) && (ibuffered > 0)) { + bytes[ofs++] = iBuffer[IBUFFER_SIZE - ibuffered--]; + } + } + } + } else { + // avoid using the buffer - just fill bytes directly + implNextBytes(bytes); + } + + } + + // see JCA spec + @Override + protected byte[] engineGenerateSeed(int numBytes) { + byte[] b = new byte[numBytes]; + engineNextBytes(b); + return b; + } + + private void mix(byte[] b) { + SecureRandom random = mixRandom; + if (random == null) { + // avoid mixing if setSeed() has never been called + return; + } + synchronized (this) { + int ofs = 0; + int len = b.length; + while (len-- > 0) { + if (buffered == 0) { + random.nextBytes(mixBuffer); + buffered = mixBuffer.length; + } + b[ofs++] ^= mixBuffer[mixBuffer.length - buffered]; + buffered--; + } + } + } + + // fill up the specified buffer with random bytes, and mix them + private void implNextBytes(byte[] bytes) { + Session session = null; + try { + session = token.getOpSession(); + token.p11.C_GenerateRandom(session.id(), bytes); + mix(bytes); + } catch (PKCS11Exception e) { + throw new ProviderException("nextBytes() failed", e); + } finally { + token.releaseSession(session); + } + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + // assign default values to non-null transient fields + iBuffer = new byte[IBUFFER_SIZE]; + ibuffered = 0; + lastRead = 0L; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11Signature.java b/src/main/java/com/sunyard/security/pkcs11/P11Signature.java new file mode 100644 index 0000000..59efa79 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11Signature.java @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; + +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.AlgorithmParameterSpec; +import sun.nio.ch.DirectBuffer; + +import sun.security.util.*; +import sun.security.x509.AlgorithmId; + +import sun.security.rsa.RSASignature; +import sun.security.rsa.RSAPadding; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; +import sun.security.util.KeyUtil; + +import javax.crypto.BadPaddingException; + +/** + * Signature implementation class. This class currently supports the + * following algorithms: + * + * . DSA + * . NONEwithDSA (RawDSA) + * . SHA1withDSA + * . RSA: + * . MD2withRSA + * . MD5withRSA + * . SHA1withRSA + * . SHA224withRSA + * . SHA256withRSA + * . SHA384withRSA + * . SHA512withRSA + * . ECDSA + * . NONEwithECDSA + * . SHA1withECDSA + * . SHA224withECDSA + * . SHA256withECDSA + * . SHA384withECDSA + * . SHA512withECDSA + * + * Note that the underlying PKCS#11 token may support complete signature + * algorithm (e.g. CKM_DSA_SHA1, CKM_MD5_RSA_PKCS), or it may just + * implement the signature algorithm without hashing (e.g. CKM_DSA, CKM_PKCS), + * or it may only implement the raw public key operation (CKM_RSA_X_509). + * This class uses what is available and adds whatever extra processing + * is needed. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class P11Signature extends SignatureSpi { + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // name of the key algorithm, currently either RSA or DSA + private final String keyAlgorithm; + + // mechanism id + private final long mechanism; + + // digest algorithm OID, if we encode RSA signature ourselves + private final ObjectIdentifier digestOID; + + // type, one of T_* below + private final int type; + + // key instance used, if init*() was called + private P11Key p11Key; + + // message digest, if we do the digesting ourselves + private final MessageDigest md; + + // associated session, if any + private Session session; + + // mode, one of M_* below + private int mode; + + // flag indicating whether an operation is initialized + private boolean initialized; + + // buffer, for update(byte) or DSA + private final byte[] buffer; + + // total number of bytes processed in current operation + private int bytesProcessed; + + // constant for signing mode + private final static int M_SIGN = 1; + // constant for verification mode + private final static int M_VERIFY = 2; + + // constant for type digesting, we do the hashing ourselves + private final static int T_DIGEST = 1; + // constant for type update, token does everything + private final static int T_UPDATE = 2; + // constant for type raw, used with RawDSA and NONEwithECDSA only + private final static int T_RAW = 3; + + // XXX PKCS#11 v2.20 says "should not be longer than 1024 bits", + // but this is a little arbitrary + private final static int RAW_ECDSA_MAX = 128; + + P11Signature(Token token, String algorithm, long mechanism) + throws NoSuchAlgorithmException, PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + byte[] buffer = null; + ObjectIdentifier digestOID = null; + MessageDigest md = null; + switch ((int)mechanism) { + case (int)CKM_MD2_RSA_PKCS: + case (int)CKM_MD5_RSA_PKCS: + case (int)CKM_SHA1_RSA_PKCS: + case (int)CKM_SHA224_RSA_PKCS: + case (int)CKM_SHA256_RSA_PKCS: + case (int)CKM_SHA384_RSA_PKCS: + case (int)CKM_SHA512_RSA_PKCS: + keyAlgorithm = "RSA"; + type = T_UPDATE; + buffer = new byte[1]; + break; + case (int)CKM_DSA_SHA1: + keyAlgorithm = "DSA"; + type = T_UPDATE; + buffer = new byte[1]; + break; + case (int)CKM_ECDSA_SHA1: + keyAlgorithm = "EC"; + type = T_UPDATE; + buffer = new byte[1]; + break; + case (int)CKM_DSA: + keyAlgorithm = "DSA"; + if (algorithm.equals("DSA")) { + type = T_DIGEST; + md = MessageDigest.getInstance("SHA-1"); + } else if (algorithm.equals("RawDSA")) { + type = T_RAW; + buffer = new byte[20]; + } else { + throw new ProviderException(algorithm); + } + break; + case (int)CKM_ECDSA: + keyAlgorithm = "EC"; + if (algorithm.equals("NONEwithECDSA")) { + type = T_RAW; + buffer = new byte[RAW_ECDSA_MAX]; + } else { + String digestAlg; + if (algorithm.equals("SHA1withECDSA")) { + digestAlg = "SHA-1"; + } else if (algorithm.equals("SHA224withECDSA")) { + digestAlg = "SHA-224"; + } else if (algorithm.equals("SHA256withECDSA")) { + digestAlg = "SHA-256"; + } else if (algorithm.equals("SHA384withECDSA")) { + digestAlg = "SHA-384"; + } else if (algorithm.equals("SHA512withECDSA")) { + digestAlg = "SHA-512"; + } else { + throw new ProviderException(algorithm); + } + type = T_DIGEST; + md = MessageDigest.getInstance(digestAlg); + } + break; + case (int)CKM_RSA_PKCS: + case (int)CKM_RSA_X_509: + keyAlgorithm = "RSA"; + type = T_DIGEST; + if (algorithm.equals("MD5withRSA")) { + md = MessageDigest.getInstance("MD5"); + digestOID = AlgorithmId.MD5_oid; + } else if (algorithm.equals("SHA1withRSA")) { + md = MessageDigest.getInstance("SHA-1"); + digestOID = AlgorithmId.SHA_oid; + } else if (algorithm.equals("MD2withRSA")) { + md = MessageDigest.getInstance("MD2"); + digestOID = AlgorithmId.MD2_oid; + } else if (algorithm.equals("SHA224withRSA")) { + md = MessageDigest.getInstance("SHA-224"); + digestOID = AlgorithmId.SHA224_oid; + } else if (algorithm.equals("SHA256withRSA")) { + md = MessageDigest.getInstance("SHA-256"); + digestOID = AlgorithmId.SHA256_oid; + } else if (algorithm.equals("SHA384withRSA")) { + md = MessageDigest.getInstance("SHA-384"); + digestOID = AlgorithmId.SHA384_oid; + } else if (algorithm.equals("SHA512withRSA")) { + md = MessageDigest.getInstance("SHA-512"); + digestOID = AlgorithmId.SHA512_oid; + } else { + throw new ProviderException("Unknown signature: " + algorithm); + } + break; + default: + throw new ProviderException("Unknown mechanism: " + mechanism); + } + this.buffer = buffer; + this.digestOID = digestOID; + this.md = md; + } + + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + + if (!initialized) { + return; + } + initialized = false; + + try { + if (session == null) { + return; + } + + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + } + } + + private void cancelOperation() { + token.ensureValid(); + // cancel operation by finishing it; avoid killSession as some + // hardware vendors may require re-login + try { + if (mode == M_SIGN) { + if (type == T_UPDATE) { + token.p11.C_SignFinal(session.id(), 0); + } else { + byte[] digest; + if (type == T_DIGEST) { + digest = md.digest(); + } else { // T_RAW + digest = buffer; + } + token.p11.C_Sign(session.id(), digest); + } + } else { // M_VERIFY + byte[] signature; + if (keyAlgorithm.equals("DSA")) { + signature = new byte[40]; + } else { + signature = new byte[(p11Key.length() + 7) >> 3]; + } + if (type == T_UPDATE) { + token.p11.C_VerifyFinal(session.id(), signature); + } else { + byte[] digest; + if (type == T_DIGEST) { + digest = md.digest(); + } else { // T_RAW + digest = buffer; + } + token.p11.C_Verify(session.id(), digest, signature); + } + } + } catch (PKCS11Exception e) { + if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { + // Cancel Operation may be invoked after an error on a PKCS#11 + // call. If the operation inside the token was already cancelled, + // do not fail here. This is part of a defensive mechanism for + // PKCS#11 libraries that do not strictly follow the standard. + return; + } + if (mode == M_VERIFY) { + long errorCode = e.getErrorCode(); + if ((errorCode == CKR_SIGNATURE_INVALID) || + (errorCode == CKR_SIGNATURE_LEN_RANGE)) { + // expected since signature is incorrect + return; + } + } + throw new ProviderException("cancel failed", e); + } + } + + private void ensureInitialized() { + + if (!initialized) { + initialize(); + } + } + + // assumes current state is initialized == false + private void initialize() { + + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without " + + "calling engineInit first"); + } + long keyID = p11Key.getKeyID(); + try { + token.ensureValid(); + if (session == null) { + session = token.getOpSession(); + } + if (mode == M_SIGN) { + token.p11.C_SignInit(session.id(), + new CK_MECHANISM(mechanism), keyID); + } else { + token.p11.C_VerifyInit(session.id(), + new CK_MECHANISM(mechanism), keyID); + } + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw new ProviderException("Initialization failed", e); + } + if (bytesProcessed != 0) { + bytesProcessed = 0; + if (md != null) { + md.reset(); + } + } + initialized = true; + } + + private void checkKeySize(String keyAlgo, Key key) + throws InvalidKeyException { + CK_MECHANISM_INFO mechInfo = null; + try { + mechInfo = token.getMechanismInfo(mechanism); + } catch (PKCS11Exception e) { + // should not happen, ignore for now. + } + if (mechInfo == null) { + // skip the check if no native info available + return; + } + int minKeySize = mechInfo.iMinKeySize; + int maxKeySize = mechInfo.iMaxKeySize; + + // need to override the MAX keysize for SHA1withDSA + if (md != null && mechanism == CKM_DSA && maxKeySize > 1024) { + maxKeySize = 1024; + } + int keySize = 0; + if (key instanceof P11Key) { + keySize = ((P11Key) key).length(); + } else { + try { + if (keyAlgo.equals("RSA")) { + keySize = ((RSAKey) key).getModulus().bitLength(); + } else if (keyAlgo.equals("DSA")) { + keySize = ((DSAKey) key).getParams().getP().bitLength(); + } else if (keyAlgo.equals("EC")) { + keySize = ((ECKey) key).getParams().getCurve().getField().getFieldSize(); + } else { + throw new ProviderException("Error: unsupported algo " + keyAlgo); + } + } catch (ClassCastException cce) { + throw new InvalidKeyException(keyAlgo + + " key must be the right type", cce); + } + } + if (keySize < minKeySize) { + throw new InvalidKeyException(keyAlgo + + " key must be at least " + minKeySize + " bits"); + } + if (keySize > maxKeySize) { + throw new InvalidKeyException(keyAlgo + + " key must be at most " + maxKeySize + " bits"); + } + if (keyAlgo.equals("RSA")) { + checkRSAKeyLength(keySize); + } + } + + private void checkRSAKeyLength(int len) throws InvalidKeyException { + RSAPadding padding; + try { + padding = RSAPadding.getInstance + (RSAPadding.PAD_BLOCKTYPE_1, (len + 7) >> 3); + } catch (InvalidAlgorithmParameterException iape) { + throw new InvalidKeyException(iape.getMessage()); + } + int maxDataSize = padding.getMaxDataSize(); + int encodedLength; + if (algorithm.equals("MD5withRSA") || + algorithm.equals("MD2withRSA")) { + encodedLength = 34; + } else if (algorithm.equals("SHA1withRSA")) { + encodedLength = 35; + } else if (algorithm.equals("SHA224withRSA")) { + encodedLength = 47; + } else if (algorithm.equals("SHA256withRSA")) { + encodedLength = 51; + } else if (algorithm.equals("SHA384withRSA")) { + encodedLength = 67; + } else if (algorithm.equals("SHA512withRSA")) { + encodedLength = 83; + } else { + throw new ProviderException("Unknown signature algo: " + algorithm); + } + if (encodedLength > maxDataSize) { + throw new InvalidKeyException + ("Key is too short for this signature algorithm"); + } + } + + // see JCA spec + @Override + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException { + if (publicKey == null) { + throw new InvalidKeyException("Key must not be null"); + } + // Need to check key length whenever a new key is set + if (publicKey != p11Key) { + checkKeySize(keyAlgorithm, publicKey); + } + reset(true); + mode = M_VERIFY; + p11Key = P11KeyFactory.convertKey(token, publicKey, keyAlgorithm); + initialize(); + } + + // see JCA spec + @Override + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException { + if (privateKey == null) { + throw new InvalidKeyException("Key must not be null"); + } + // Need to check RSA key length whenever a new key is set + if (privateKey != p11Key) { + checkKeySize(keyAlgorithm, privateKey); + } + reset(true); + mode = M_SIGN; + p11Key = P11KeyFactory.convertKey(token, privateKey, keyAlgorithm); + initialize(); + } + + // see JCA spec + @Override + protected void engineUpdate(byte b) throws SignatureException { + ensureInitialized(); + switch (type) { + case T_UPDATE: + buffer[0] = b; + engineUpdate(buffer, 0, 1); + break; + case T_DIGEST: + md.update(b); + bytesProcessed++; + break; + case T_RAW: + if (bytesProcessed >= buffer.length) { + bytesProcessed = buffer.length + 1; + return; + } + buffer[bytesProcessed++] = b; + break; + default: + throw new ProviderException("Internal error"); + } + } + + // see JCA spec + @Override + protected void engineUpdate(byte[] b, int ofs, int len) + throws SignatureException { + + ensureInitialized(); + if (len == 0) { + return; + } + // check for overflow + if (len + bytesProcessed < 0) { + throw new ProviderException("Processed bytes limits exceeded."); + } + switch (type) { + case T_UPDATE: + try { + if (mode == M_SIGN) { + token.p11.C_SignUpdate(session.id(), 0, b, ofs, len); + } else { + token.p11.C_VerifyUpdate(session.id(), 0, b, ofs, len); + } + bytesProcessed += len; + } catch (PKCS11Exception e) { + reset(false); + throw new ProviderException(e); + } + break; + case T_DIGEST: + md.update(b, ofs, len); + bytesProcessed += len; + break; + case T_RAW: + if (bytesProcessed + len > buffer.length) { + bytesProcessed = buffer.length + 1; + return; + } + System.arraycopy(b, ofs, buffer, bytesProcessed, len); + bytesProcessed += len; + break; + default: + throw new ProviderException("Internal error"); + } + } + + // see JCA spec + @Override + protected void engineUpdate(ByteBuffer byteBuffer) { + + ensureInitialized(); + int len = byteBuffer.remaining(); + if (len <= 0) { + return; + } + switch (type) { + case T_UPDATE: + if (byteBuffer instanceof DirectBuffer == false) { + // cannot do better than default impl + super.engineUpdate(byteBuffer); + return; + } + long addr = ((DirectBuffer)byteBuffer).address(); + int ofs = byteBuffer.position(); + try { + if (mode == M_SIGN) { + token.p11.C_SignUpdate + (session.id(), addr + ofs, null, 0, len); + } else { + token.p11.C_VerifyUpdate + (session.id(), addr + ofs, null, 0, len); + } + bytesProcessed += len; + byteBuffer.position(ofs + len); + } catch (PKCS11Exception e) { + reset(false); + throw new ProviderException("Update failed", e); + } + break; + case T_DIGEST: + md.update(byteBuffer); + bytesProcessed += len; + break; + case T_RAW: + if (bytesProcessed + len > buffer.length) { + bytesProcessed = buffer.length + 1; + return; + } + byteBuffer.get(buffer, bytesProcessed, len); + bytesProcessed += len; + break; + default: + reset(false); + throw new ProviderException("Internal error"); + } + } + + // see JCA spec + @Override + protected byte[] engineSign() throws SignatureException { + + ensureInitialized(); + boolean doCancel = true; + try { + byte[] signature; + if (type == T_UPDATE) { + int len = keyAlgorithm.equals("DSA") ? 40 : 0; + signature = token.p11.C_SignFinal(session.id(), len); + } else { + byte[] digest; + if (type == T_DIGEST) { + digest = md.digest(); + } else { // T_RAW + if (mechanism == CKM_DSA) { + if (bytesProcessed != buffer.length) { + throw new SignatureException + ("Data for RawDSA must be exactly 20 bytes long"); + } + digest = buffer; + } else { // CKM_ECDSA + if (bytesProcessed > buffer.length) { + throw new SignatureException("Data for NONEwithECDSA" + + " must be at most " + RAW_ECDSA_MAX + " bytes long"); + } + digest = new byte[bytesProcessed]; + System.arraycopy(buffer, 0, digest, 0, bytesProcessed); + } + } + if (keyAlgorithm.equals("RSA") == false) { + // DSA and ECDSA + signature = token.p11.C_Sign(session.id(), digest); + } else { // RSA + byte[] data = encodeSignature(digest); + if (mechanism == CKM_RSA_X_509) { + data = pkcs1Pad(data); + } + signature = token.p11.C_Sign(session.id(), data); + } + } + doCancel = false; + + if (keyAlgorithm.equals("RSA") == false) { + return dsaToASN1(signature); + } else { + return signature; + } + } catch (PKCS11Exception | BadPaddingException e) { + // As per the PKCS#11 standard, C_Sign and C_SignFinal may only + // keep the operation active on CKR_BUFFER_TOO_SMALL errors or + // successful calls to determine the output length. However, + // these cases are handled at OpenJDK's libj2pkcs11 native + // library. Thus, doCancel can safely be 'false' here. + doCancel = false; + throw new ProviderException(e); + } finally { + reset(doCancel); + } + } + + // see JCA spec + @Override + protected boolean engineVerify(byte[] signature) throws SignatureException { + ensureInitialized(); + boolean doCancel = true; + try { + if (keyAlgorithm.equals("DSA")) { + signature = asn1ToDSA(signature); + } else if (keyAlgorithm.equals("EC")) { + signature = asn1ToECDSA(signature); + } + if (type == T_UPDATE) { + token.p11.C_VerifyFinal(session.id(), signature); + } else { + byte[] digest; + if (type == T_DIGEST) { + digest = md.digest(); + } else { // T_RAW + if (mechanism == CKM_DSA) { + if (bytesProcessed != buffer.length) { + throw new SignatureException + ("Data for RawDSA must be exactly 20 bytes long"); + } + digest = buffer; + } else { + if (bytesProcessed > buffer.length) { + throw new SignatureException("Data for NONEwithECDSA" + + " must be at most " + RAW_ECDSA_MAX + " bytes long"); + } + digest = new byte[bytesProcessed]; + System.arraycopy(buffer, 0, digest, 0, bytesProcessed); + } + } + if (keyAlgorithm.equals("RSA") == false) { + // DSA and ECDSA + token.p11.C_Verify(session.id(), digest, signature); + } else { // RSA + byte[] data = encodeSignature(digest); + if (mechanism == CKM_RSA_X_509) { + try { + data = pkcs1Pad(data); + } catch (BadPaddingException e) { + throw new RuntimeException(e); + } + } + token.p11.C_Verify(session.id(), data, signature); + } + } + doCancel = false; + return true; + } catch (PKCS11Exception e) { + doCancel = false; + long errorCode = e.getErrorCode(); + if (errorCode == CKR_SIGNATURE_INVALID) { + return false; + } + if (errorCode == CKR_SIGNATURE_LEN_RANGE) { + // return false rather than throwing an exception + return false; + } + // ECF bug? + if (errorCode == CKR_DATA_LEN_RANGE) { + return false; + } + throw new ProviderException(e); + } finally { + reset(doCancel); + } + } + + private byte[] pkcs1Pad(byte[] data) throws BadPaddingException { + try { + int len = (p11Key.length() + 7) >> 3; + RSAPadding padding = RSAPadding.getInstance + (RSAPadding.PAD_BLOCKTYPE_1, len); + byte[] result = padding.pad(data); + if (result == null) { + throw new ProviderException("Error padding data"); + } + return result; + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new ProviderException(e); + } + } + + private byte[] encodeSignature(byte[] digest) throws SignatureException { + try { + return RSASignature.encodeSignature(digestOID, digest); + } catch (IOException e) { + throw new SignatureException("Invalid encoding", e); + } + } + +// private static byte[] decodeSignature(byte[] signature) throws IOException { +// return RSASignature.decodeSignature(digestOID, signature); +// } + + // For DSA and ECDSA signatures, PKCS#11 represents them as a simple + // byte array that contains the concatenation of r and s. + // For DSA, r and s are always exactly 20 bytes long. + // For ECDSA, r and s are of variable length, but we know that each + // occupies half of the array. + private static byte[] dsaToASN1(byte[] signature) { + int n = signature.length >> 1; + BigInteger r = new BigInteger(1, P11Util.subarray(signature, 0, n)); + BigInteger s = new BigInteger(1, P11Util.subarray(signature, n, n)); + try { + DerOutputStream outseq = new DerOutputStream(100); + outseq.putInteger(r); + outseq.putInteger(s); + DerValue result = new DerValue(DerValue.tag_Sequence, + outseq.toByteArray()); + return result.toByteArray(); + } catch (java.io.IOException e) { + throw new RuntimeException("Internal error", e); + } + } + + private static byte[] asn1ToDSA(byte[] sig) throws SignatureException { + try { + // Enforce strict DER checking for signatures + DerInputStream in = new DerInputStream(sig, 0, sig.length, false); + DerValue[] values = in.getSequence(2); + + // check number of components in the read sequence + // and trailing data + if ((values.length != 2) || (in.available() != 0)) { + throw new IOException("Invalid encoding for signature"); + } + + BigInteger r = values[0].getPositiveBigInteger(); + BigInteger s = values[1].getPositiveBigInteger(); + + byte[] br = toByteArray(r, 20); + byte[] bs = toByteArray(s, 20); + if ((br == null) || (bs == null)) { + throw new SignatureException("Out of range value for R or S"); + } + return P11Util.concat(br, bs); + } catch (SignatureException e) { + throw e; + } catch (Exception e) { + throw new SignatureException("Invalid encoding for signature", e); + } + } + + private byte[] asn1ToECDSA(byte[] sig) throws SignatureException { + try { + // Enforce strict DER checking for signatures + DerInputStream in = new DerInputStream(sig, 0, sig.length, false); + DerValue[] values = in.getSequence(2); + + // check number of components in the read sequence + // and trailing data + if ((values.length != 2) || (in.available() != 0)) { + throw new IOException("Invalid encoding for signature"); + } + + BigInteger r = values[0].getPositiveBigInteger(); + BigInteger s = values[1].getPositiveBigInteger(); + + // trim leading zeroes + byte[] br = KeyUtil.trimZeroes(r.toByteArray()); + byte[] bs = KeyUtil.trimZeroes(s.toByteArray()); + int k = Math.max(br.length, bs.length); + // r and s each occupy half the array + byte[] res = new byte[k << 1]; + System.arraycopy(br, 0, res, k - br.length, br.length); + System.arraycopy(bs, 0, res, res.length - bs.length, bs.length); + return res; + } catch (Exception e) { + throw new SignatureException("Invalid encoding for signature", e); + } + } + + private static byte[] toByteArray(BigInteger bi, int len) { + byte[] b = bi.toByteArray(); + int n = b.length; + if (n == len) { + return b; + } + if ((n == len + 1) && (b[0] == 0)) { + byte[] t = new byte[len]; + System.arraycopy(b, 1, t, 0, len); + return t; + } + if (n > len) { + return null; + } + // must be smaller + byte[] t = new byte[len]; + System.arraycopy(b, 0, t, (len - n), n); + return t; + } + + // see JCA spec + @Override + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new UnsupportedOperationException("setParameter() not supported"); + } + + // see JCA spec + @Override + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException("No parameter accepted"); + } + } + + // see JCA spec + @Override + protected Object engineGetParameter(String param) + throws InvalidParameterException { + throw new UnsupportedOperationException("getParameter() not supported"); + } + + // see JCA spec + @Override + protected AlgorithmParameters engineGetParameters() { + return null; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11TlsKeyMaterialGenerator.java b/src/main/java/com/sunyard/security/pkcs11/P11TlsKeyMaterialGenerator.java new file mode 100644 index 0000000..c8ad566 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11TlsKeyMaterialGenerator.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.security.internal.spec.*; +import sun.security.internal.interfaces.TlsMasterSecret; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * KeyGenerator to calculate the SSL/TLS key material (cipher keys and ivs, + * mac keys) from the master secret. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi { + + private final static String MSG = "TlsKeyMaterialGenerator must be " + + "initialized using a TlsKeyMaterialParameterSpec"; + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private long mechanism; + + // parameter spec + private TlsKeyMaterialParameterSpec spec; + + // master secret as a P11Key + private P11Key p11Key; + + // version, e.g. 0x0301 + private int version; + + P11TlsKeyMaterialGenerator(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + } + + protected void engineInit(SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected void engineInit(AlgorithmParameterSpec params, + SecureRandom random) throws InvalidAlgorithmParameterException { + if (params instanceof TlsKeyMaterialParameterSpec == false) { + throw new InvalidAlgorithmParameterException(MSG); + } + this.spec = (TlsKeyMaterialParameterSpec)params; + try { + p11Key = P11SecretKeyFactory.convertKey + (token, spec.getMasterSecret(), "TlsMasterSecret"); + } catch (InvalidKeyException e) { + throw new InvalidAlgorithmParameterException("init() failed", e); + } + version = (spec.getMajorVersion() << 8) | spec.getMinorVersion(); + if ((version < 0x0300) && (version > 0x0303)) { + throw new InvalidAlgorithmParameterException("Only SSL 3.0," + + " TLS 1.0, TLS 1.1, and TLS 1.2 are supported"); + } + // we assume the token supports both the CKM_SSL3_* and the CKM_TLS_* + // mechanisms + } + + protected void engineInit(int keysize, SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected SecretKey engineGenerateKey() { + if (spec == null) { + throw new IllegalStateException + ("TlsKeyMaterialGenerator must be initialized"); + } + if (version == 0x0300) { + mechanism = CKM_SSL3_KEY_AND_MAC_DERIVE; + } else if (version == 0x0301 || version == 0x0302) { + mechanism = CKM_TLS_KEY_AND_MAC_DERIVE; + } + int macBits = spec.getMacKeyLength() << 3; + int ivBits = spec.getIvLength() << 3; + + int expandedKeyBits = spec.getExpandedCipherKeyLength() << 3; + int keyBits = spec.getCipherKeyLength() << 3; + boolean isExportable; + if (expandedKeyBits != 0) { + isExportable = true; + } else { + isExportable = false; + expandedKeyBits = keyBits; + } + + CK_SSL3_RANDOM_DATA random = new CK_SSL3_RANDOM_DATA + (spec.getClientRandom(), spec.getServerRandom()); + Object params = null; + CK_MECHANISM ckMechanism = null; + if (version < 0x0303) { + params = new CK_SSL3_KEY_MAT_PARAMS + (macBits, keyBits, ivBits, isExportable, random); + ckMechanism = new CK_MECHANISM(mechanism, (CK_SSL3_KEY_MAT_PARAMS)params); + } else if (version == 0x0303) { + params = new CK_TLS12_KEY_MAT_PARAMS + (macBits, keyBits, ivBits, isExportable, random, + Functions.getHashMechId(spec.getPRFHashAlg())); + ckMechanism = new CK_MECHANISM(mechanism, (CK_TLS12_KEY_MAT_PARAMS)params); + } + + String cipherAlgorithm = spec.getCipherAlgorithm(); + long keyType = P11SecretKeyFactory.getKeyType(cipherAlgorithm); + if (keyType < 0) { + if (keyBits != 0) { + throw new ProviderException + ("Unknown algorithm: " + spec.getCipherAlgorithm()); + } else { + // NULL encryption ciphersuites + keyType = CKK_GENERIC_SECRET; + } + } + + Session session = null; + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes; + if (keyBits != 0) { + attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + new CK_ATTRIBUTE(CKA_VALUE_LEN, expandedKeyBits >> 3), + }; + } else { + // ciphersuites with NULL ciphers + attributes = new CK_ATTRIBUTE[0]; + } + attributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); + long p11KeyID = p11Key.getKeyID(); + try { + token.p11.C_DeriveKey(session.id(), + ckMechanism, p11KeyID, attributes); + } finally { + p11Key.releaseKeyID(); + } + + CK_SSL3_KEY_MAT_OUT out = null; + if (params instanceof CK_SSL3_KEY_MAT_PARAMS) { + out = ((CK_SSL3_KEY_MAT_PARAMS)params).pReturnedKeyMaterial; + } else if (params instanceof CK_TLS12_KEY_MAT_PARAMS) { + out = ((CK_TLS12_KEY_MAT_PARAMS)params).pReturnedKeyMaterial; + } + // Note that the MAC keys do not inherit all attributes from the + // template, but they do inherit the sensitive/extractable/token + // flags, which is all P11Key cares about. + SecretKey clientMacKey, serverMacKey; + + // The MAC size may be zero for GCM mode. + // + // PKCS11 does not support GCM mode as the author made the comment, + // so the macBits is unlikely to be zero. It's only a place holder. + if (macBits != 0) { + clientMacKey = P11Key.secretKey + (session, out.hClientMacSecret, "MAC", macBits, attributes); + serverMacKey = P11Key.secretKey + (session, out.hServerMacSecret, "MAC", macBits, attributes); + } else { + clientMacKey = null; + serverMacKey = null; + } + + SecretKey clientCipherKey, serverCipherKey; + if (keyBits != 0) { + clientCipherKey = P11Key.secretKey(session, out.hClientKey, + cipherAlgorithm, expandedKeyBits, attributes); + serverCipherKey = P11Key.secretKey(session, out.hServerKey, + cipherAlgorithm, expandedKeyBits, attributes); + } else { + clientCipherKey = null; + serverCipherKey = null; + } + IvParameterSpec clientIv = (out.pIVClient == null) + ? null : new IvParameterSpec(out.pIVClient); + IvParameterSpec serverIv = (out.pIVServer == null) + ? null : new IvParameterSpec(out.pIVServer); + + return new TlsKeyMaterialSpec(clientMacKey, serverMacKey, + clientCipherKey, clientIv, serverCipherKey, serverIv); + + } catch (Exception e) { + throw new ProviderException("Could not generate key", e); + } finally { + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11TlsMasterSecretGenerator.java b/src/main/java/com/sunyard/security/pkcs11/P11TlsMasterSecretGenerator.java new file mode 100644 index 0000000..51b0ac2 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11TlsMasterSecretGenerator.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.security.internal.spec.TlsMasterSecretParameterSpec; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * KeyGenerator for the SSL/TLS master secret. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +public final class P11TlsMasterSecretGenerator extends KeyGeneratorSpi { + + private final static String MSG = "TlsMasterSecretGenerator must be " + + "initialized using a TlsMasterSecretParameterSpec"; + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private long mechanism; + + private TlsMasterSecretParameterSpec spec; + private P11Key p11Key; + + int version; + + P11TlsMasterSecretGenerator(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + } + + protected void engineInit(SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected void engineInit(AlgorithmParameterSpec params, + SecureRandom random) throws InvalidAlgorithmParameterException { + if (params instanceof TlsMasterSecretParameterSpec == false) { + throw new InvalidAlgorithmParameterException(MSG); + } + this.spec = (TlsMasterSecretParameterSpec)params; + SecretKey key = spec.getPremasterSecret(); + // algorithm should be either TlsRsaPremasterSecret or TlsPremasterSecret, + // but we omit the check + try { + p11Key = P11SecretKeyFactory.convertKey(token, key, null); + } catch (InvalidKeyException e) { + throw new InvalidAlgorithmParameterException("init() failed", e); + } + version = (spec.getMajorVersion() << 8) | spec.getMinorVersion(); + if ((version < 0x0300) && (version > 0x0303)) { + throw new InvalidAlgorithmParameterException("Only SSL 3.0," + + " TLS 1.0, TLS 1.1, and TLS 1.2 are supported"); + } + // We assume the token supports the required mechanism. If it does not, + // generateKey() will fail and the failover should take care of us. + } + + protected void engineInit(int keysize, SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected SecretKey engineGenerateKey() { + if (spec == null) { + throw new IllegalStateException + ("TlsMasterSecretGenerator must be initialized"); + } + final boolean isTlsRsaPremasterSecret = + p11Key.getAlgorithm().equals("TlsRsaPremasterSecret"); + if (version == 0x0300) { + mechanism = isTlsRsaPremasterSecret ? + CKM_SSL3_MASTER_KEY_DERIVE : CKM_SSL3_MASTER_KEY_DERIVE_DH; + } else if (version == 0x0301 || version == 0x0302) { + mechanism = isTlsRsaPremasterSecret ? + CKM_TLS_MASTER_KEY_DERIVE : CKM_TLS_MASTER_KEY_DERIVE_DH; + } else if (version == 0x0303) { + mechanism = isTlsRsaPremasterSecret ? + CKM_TLS12_MASTER_KEY_DERIVE : CKM_TLS12_MASTER_KEY_DERIVE_DH; + } + CK_VERSION ckVersion; + if (isTlsRsaPremasterSecret) { + ckVersion = new CK_VERSION(0, 0); + } else { + // Note: we use DH for all non-RSA premaster secrets. That includes + // Kerberos. That should not be a problem because master secret + // calculation is always a straightforward application of the + // TLS PRF (or the SSL equivalent). + // The only thing special about RSA master secret calculation is + // that it extracts the version numbers from the premaster secret. + ckVersion = null; + } + byte[] clientRandom = spec.getClientRandom(); + byte[] serverRandom = spec.getServerRandom(); + CK_SSL3_RANDOM_DATA random = + new CK_SSL3_RANDOM_DATA(clientRandom, serverRandom); + CK_MECHANISM ckMechanism = null; + if (version < 0x0303) { + CK_SSL3_MASTER_KEY_DERIVE_PARAMS params = + new CK_SSL3_MASTER_KEY_DERIVE_PARAMS(random, ckVersion); + ckMechanism = new CK_MECHANISM(mechanism, params); + } else if (version == 0x0303) { + CK_TLS12_MASTER_KEY_DERIVE_PARAMS params = + new CK_TLS12_MASTER_KEY_DERIVE_PARAMS(random, ckVersion, + Functions.getHashMechId(spec.getPRFHashAlg())); + ckMechanism = new CK_MECHANISM(mechanism, params); + } + + Session session = null; + long p11KeyID = p11Key.getKeyID(); + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes = token.getAttributes(O_GENERATE, + CKO_SECRET_KEY, CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_DeriveKey(session.id(), + ckMechanism, p11KeyID, attributes); + int major, minor; + if (ckVersion == null) { + major = -1; + minor = -1; + } else { + major = ckVersion.major; + minor = ckVersion.minor; + } + return P11Key.masterSecretKey(session, keyID, + "TlsMasterSecret", 48 << 3, attributes, major, minor); + } catch (Exception e) { + throw new ProviderException("Could not generate key", e); + } finally { + p11Key.releaseKeyID(); + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11TlsPrfGenerator.java b/src/main/java/com/sunyard/security/pkcs11/P11TlsPrfGenerator.java new file mode 100644 index 0000000..7fa650f --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11TlsPrfGenerator.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.security.internal.spec.TlsPrfParameterSpec; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * KeyGenerator for the TLS PRF. Note that although the PRF is used in a number + * of places during the handshake, this class is usually only used to calculate + * the Finished messages. The reason is that for those other uses more specific + * PKCS#11 mechanisms have been defined (CKM_SSL3_MASTER_KEY_DERIVE, etc.). + * + *

This class supports the CKM_TLS_PRF mechanism from PKCS#11 v2.20 and + * the older NSS private mechanism. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +final class P11TlsPrfGenerator extends KeyGeneratorSpi { + + private final static String MSG = + "TlsPrfGenerator must be initialized using a TlsPrfParameterSpec"; + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private final long mechanism; + + private TlsPrfParameterSpec spec; + + private P11Key p11Key; + + P11TlsPrfGenerator(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + } + + protected void engineInit(SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected void engineInit(AlgorithmParameterSpec params, + SecureRandom random) throws InvalidAlgorithmParameterException { + if (params instanceof TlsPrfParameterSpec == false) { + throw new InvalidAlgorithmParameterException(MSG); + } + this.spec = (TlsPrfParameterSpec)params; + SecretKey key = spec.getSecret(); + if (key == null) { + key = NULL_KEY; + } + try { + p11Key = P11SecretKeyFactory.convertKey(token, key, null); + } catch (InvalidKeyException e) { + throw new InvalidAlgorithmParameterException("init() failed", e); + } + } + + // SecretKeySpec does not allow zero length keys, so we define our + // own class. + // + // As an anonymous class cannot make any guarantees about serialization + // compatibility, it is nonsensical for an anonymous class to define a + // serialVersionUID. Suppress warnings relative to missing serialVersionUID + // field in the anonymous subclass of serializable SecretKey. + @SuppressWarnings("serial") + private static final SecretKey NULL_KEY = new SecretKey() { + public byte[] getEncoded() { + return new byte[0]; + } + public String getFormat() { + return "RAW"; + } + public String getAlgorithm() { + return "Generic"; + } + }; + + protected void engineInit(int keysize, SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected SecretKey engineGenerateKey() { + if (spec == null) { + throw new IllegalStateException("TlsPrfGenerator must be initialized"); + } + byte[] seed = spec.getSeed(); + + // TLS 1.2 + if (mechanism == CKM_TLS_MAC) { + SecretKey k = null; + int ulServerOrClient = 0; + if (spec.getLabel().equals("server finished")) { + ulServerOrClient = 1; + } + if (spec.getLabel().equals("client finished")) { + ulServerOrClient = 2; + } + + if (ulServerOrClient != 0) { + // Finished message + CK_TLS_MAC_PARAMS params = new CK_TLS_MAC_PARAMS( + Functions.getHashMechId(spec.getPRFHashAlg()), + spec.getOutputLength(), ulServerOrClient); + Session session = null; + long keyID = p11Key.getKeyID(); + try { + session = token.getOpSession(); + token.p11.C_SignInit(session.id(), + new CK_MECHANISM(mechanism, params), keyID); + token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); + byte[] out = token.p11.C_SignFinal + (session.id(), spec.getOutputLength()); + return new SecretKeySpec(out, "TlsPrf"); + } catch (PKCS11Exception e) { + throw new ProviderException("Could not calculate PRF", e); + } finally { + p11Key.releaseKeyID(); + token.releaseSession(session); + } + } else { + throw new ProviderException("Only Finished message authentication code"+ + " generation supported for TLS 1.2."); + } + } + + byte[] label = P11Util.getBytesUTF8(spec.getLabel()); + + if (mechanism == CKM_NSS_TLS_PRF_GENERAL) { + Session session = null; + long keyID = p11Key.getKeyID(); + try { + session = token.getOpSession(); + token.p11.C_SignInit + (session.id(), new CK_MECHANISM(mechanism), keyID); + token.p11.C_SignUpdate(session.id(), 0, label, 0, label.length); + token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); + byte[] out = token.p11.C_SignFinal + (session.id(), spec.getOutputLength()); + return new SecretKeySpec(out, "TlsPrf"); + } catch (PKCS11Exception e) { + throw new ProviderException("Could not calculate PRF", e); + } finally { + p11Key.releaseKeyID(); + token.releaseSession(session); + } + } + + // mechanism == CKM_TLS_PRF + + byte[] out = new byte[spec.getOutputLength()]; + CK_TLS_PRF_PARAMS params = new CK_TLS_PRF_PARAMS(seed, label, out); + + Session session = null; + long keyID = p11Key.getKeyID(); + try { + session = token.getOpSession(); + token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, params), keyID, null); + return new SecretKeySpec(out, "TlsPrf"); + } catch (PKCS11Exception e) { + throw new ProviderException("Could not calculate PRF", e); + } finally { + p11Key.releaseKeyID(); + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java b/src/main/java/com/sunyard/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java new file mode 100644 index 0000000..781238f --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; + +import static com.sunyard.security.pkcs11.TemplateManager.*; +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * KeyGenerator for the SSL/TLS RSA premaster secret. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { + + private final static String MSG = "TlsRsaPremasterSecretGenerator must be " + + "initialized using a TlsRsaPremasterSecretParameterSpec"; + + // token instance + private final Token token; + + // algorithm name + private final String algorithm; + + // mechanism id + private long mechanism; + + private int version; + + private TlsRsaPremasterSecretParameterSpec spec; + + P11TlsRsaPremasterSecretGenerator(Token token, String algorithm, long mechanism) + throws PKCS11Exception { + super(); + this.token = token; + this.algorithm = algorithm; + this.mechanism = mechanism; + } + + protected void engineInit(SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + protected void engineInit(AlgorithmParameterSpec params, + SecureRandom random) throws InvalidAlgorithmParameterException { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException(MSG); + } + this.spec = (TlsRsaPremasterSecretParameterSpec)params; + version = (spec.getMajorVersion() << 8) | spec.getMinorVersion(); + if ((version < 0x0300) && (version > 0x0303)) { + throw new InvalidAlgorithmParameterException + ("Only SSL 3.0, TLS 1.0, TLS 1.1, and TLS 1.2 are supported"); + } + } + + protected void engineInit(int keysize, SecureRandom random) { + throw new InvalidParameterException(MSG); + } + + // Only can be used in client side to generate TLS RSA premaster secret. + protected SecretKey engineGenerateKey() { + if (spec == null) { + throw new IllegalStateException + ("TlsRsaPremasterSecretGenerator must be initialized"); + } + + CK_VERSION version = new CK_VERSION( + spec.getMajorVersion(), spec.getMinorVersion()); + Session session = null; + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes = token.getAttributes( + O_GENERATE, CKO_SECRET_KEY, + CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_GenerateKey(session.id(), + new CK_MECHANISM(mechanism, version), attributes); + SecretKey key = P11Key.secretKey(session, + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + return key; + } catch (PKCS11Exception e) { + throw new ProviderException( + "Could not generate premaster secret", e); + } finally { + token.releaseSession(session); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/P11Util.java b/src/main/java/com/sunyard/security/pkcs11/P11Util.java new file mode 100644 index 0000000..6fa6ec4 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/P11Util.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.math.BigInteger; +import java.security.*; + +/** + * Collection of static utility methods. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +public final class P11Util { + + private static Object LOCK = new Object(); + + private static volatile Provider sun, sunRsaSign, sunJce; + + private P11Util() { + // empty + } + + static Provider getSunProvider() { + Provider p = sun; + if (p == null) { + synchronized (LOCK) { + p = getProvider + (sun, "SUN", "sun.security.provider.Sun"); + sun = p; + } + } + return p; + } + + static Provider getSunRsaSignProvider() { + Provider p = sunRsaSign; + if (p == null) { + synchronized (LOCK) { + p = getProvider + (sunRsaSign, "SunRsaSign", "sun.security.rsa.SunRsaSign"); + sunRsaSign = p; + } + } + return p; + } + + static Provider getSunJceProvider() { + Provider p = sunJce; + if (p == null) { + synchronized (LOCK) { + p = getProvider + (sunJce, "SunJCE", "com.sun.crypto.provider.SunJCE"); + sunJce = p; + } + } + return p; + } + + private static Provider getProvider(Provider p, String providerName, + String className) { + if (p != null) { + return p; + } + p = Security.getProvider(providerName); + if (p == null) { + try { + Class clazz = Class.forName(className); + p = (Provider)clazz.newInstance(); + } catch (Exception e) { + throw new ProviderException + ("Could not find provider " + providerName, e); + } + } + return p; + } + + static byte[] convert(byte[] input, int offset, int len) { + if ((offset == 0) && (len == input.length)) { + return input; + } else { + byte[] t = new byte[len]; + System.arraycopy(input, offset, t, 0, len); + return t; + } + } + + static byte[] subarray(byte[] b, int ofs, int len) { + byte[] out = new byte[len]; + System.arraycopy(b, ofs, out, 0, len); + return out; + } + + static byte[] concat(byte[] b1, byte[] b2) { + byte[] b = new byte[b1.length + b2.length]; + System.arraycopy(b1, 0, b, 0, b1.length); + System.arraycopy(b2, 0, b, b1.length, b2.length); + return b; + } + + static long[] concat(long[] b1, long[] b2) { + if (b1.length == 0) { + return b2; + } + long[] b = new long[b1.length + b2.length]; + System.arraycopy(b1, 0, b, 0, b1.length); + System.arraycopy(b2, 0, b, b1.length, b2.length); + return b; + } + + public static byte[] getMagnitude(BigInteger bi) { + byte[] b = bi.toByteArray(); + if ((b.length > 1) && (b[0] == 0)) { + int n = b.length - 1; + byte[] newarray = new byte[n]; + System.arraycopy(b, 1, newarray, 0, n); + b = newarray; + } + return b; + } + + static byte[] getBytesUTF8(String s) { + try { + return s.getBytes("UTF8"); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + static byte[] sha1(byte[] data) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(data); + return md.digest(); + } catch (GeneralSecurityException e) { + throw new ProviderException(e); + } + } + + private final static char[] hexDigits = "0123456789abcdef".toCharArray(); + + static String toString(byte[] b) { + if (b == null) { + return "(null)"; + } + StringBuffer sb = new StringBuffer(b.length * 3); + for (int i = 0; i < b.length; i++) { + int k = b[i] & 0xff; + if (i != 0) { + sb.append(':'); + } + sb.append(hexDigits[k >>> 4]); + sb.append(hexDigits[k & 0xf]); + } + return sb.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/Secmod.java b/src/main/java/com/sunyard/security/pkcs11/Secmod.java new file mode 100644 index 0000000..33cddaf --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/Secmod.java @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.*; +import java.util.*; + +import java.security.*; +import java.security.KeyStore.*; +import java.security.cert.X509Certificate; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + + +/** + * The Secmod class defines the interface to the native NSS + * library and the configuration information it stores in its + * secmod.db file. + * + *

Example code: + *

+ *   Secmod secmod = Secmod.getInstance();
+ *   if (secmod.isInitialized() == false) {
+ *       secmod.initialize("/home/myself/.mozilla", "/usr/sfw/lib/mozilla");
+ *   }
+ *
+ *   Provider p = secmod.getModule(ModuleType.KEYSTORE).getProvider();
+ *   KeyStore ks = KeyStore.getInstance("PKCS11", p);
+ *   ks.load(null, password);
+ * 
+ * + * @since 1.6 + * @author Andreas Sterbenz + */ +public final class Secmod { + + private final static boolean DEBUG = false; + + private final static Secmod INSTANCE; + + static { + sun.security.pkcs11.wrapper.PKCS11.loadNative(); + INSTANCE = new Secmod(); + } + + private final static String NSS_LIB_NAME = "nss3"; + + private final static String SOFTTOKEN_LIB_NAME = "softokn3"; + + private final static String TRUST_LIB_NAME = "nssckbi"; + + // Slot IDs - defined in j2secmod.h on the native side + // Values obtained from NSS's pkcs11i.h header + + private final static int NETSCAPE_SLOT_ID = 0x1; + + private final static int PRIVATE_KEY_SLOT_ID = 0x2; + + private final static int FIPS_SLOT_ID = 0x3; + + // handle to be passed to the native code, 0 means not initialized + private long nssHandle; + + // whether this is a supported version of NSS + private boolean supported; + + // list of the modules + private List modules; + + private String configDir; + + private String nssLibDir; + + private Secmod() { + // empty + } + + /** + * Return the singleton Secmod instance. + */ + public static Secmod getInstance() { + return INSTANCE; + } + + private boolean isLoaded() { + if (nssHandle == 0) { + nssHandle = nssGetLibraryHandle(System.mapLibraryName(NSS_LIB_NAME)); + if (nssHandle != 0) { + fetchVersions(); + } + } + return (nssHandle != 0); + } + + private void fetchVersions() { + supported = nssVersionCheck(nssHandle, "3.7"); + } + + /** + * Test whether this Secmod has been initialized. Returns true + * if NSS has been initialized using either the initialize() method + * or by directly calling the native NSS APIs. The latter may be + * the case if the current process contains components that use + * NSS directly. + * + * @throws IOException if an incompatible version of NSS + * has been loaded + */ + public synchronized boolean isInitialized() throws IOException { + // NSS does not allow us to check if it is initialized already + // assume that if it is loaded it is also initialized + if (isLoaded() == false) { + return false; + } + if (supported == false) { + throw new IOException + ("An incompatible version of NSS is already loaded, " + + "3.7 or later required"); + } + return true; + } + + String getConfigDir() { + return configDir; + } + + String getLibDir() { + return nssLibDir; + } + + /** + * Initialize this Secmod. + * + * @param configDir the directory containing the NSS configuration + * files such as secmod.db + * @param nssLibDir the directory containing the NSS libraries + * (libnss3.so or nss3.dll) or null if the library is on + * the system default shared library path + * + * @throws IOException if NSS has already been initialized, + * the specified directories are invalid, or initialization + * fails for any other reason + */ + public void initialize(String configDir, String nssLibDir) + throws IOException { + initialize(DbMode.READ_WRITE, configDir, nssLibDir, false); + } + + public void initialize(DbMode dbMode, String configDir, String nssLibDir) + throws IOException { + initialize(dbMode, configDir, nssLibDir, false); + } + + public synchronized void initialize(DbMode dbMode, String configDir, + String nssLibDir, boolean nssOptimizeSpace) throws IOException { + + if (isInitialized()) { + throw new IOException("NSS is already initialized"); + } + + if (dbMode == null) { + throw new NullPointerException(); + } + if ((dbMode != DbMode.NO_DB) && (configDir == null)) { + throw new NullPointerException(); + } + String platformLibName = System.mapLibraryName("nss3"); + String platformPath; + if (nssLibDir == null) { + platformPath = platformLibName; + } else { + File base = new File(nssLibDir); + if (base.isDirectory() == false) { + throw new IOException("nssLibDir must be a directory:" + nssLibDir); + } + File platformFile = new File(base, platformLibName); + if (platformFile.isFile() == false) { + throw new FileNotFoundException(platformFile.getPath()); + } + platformPath = platformFile.getPath(); + } + + if (configDir != null) { + String configDirPath = null; + String sqlPrefix = "sql:"; + if (!configDir.startsWith(sqlPrefix)) { + configDirPath = configDir; + } else { + StringBuilder configDirPathSB = new StringBuilder(configDir); + configDirPath = configDirPathSB.substring(sqlPrefix.length()); + } + File configBase = new File(configDirPath); + if (configBase.isDirectory() == false ) { + throw new IOException("configDir must be a directory: " + configDirPath); + } + if (!configDir.startsWith(sqlPrefix)) { + File secmodFile = new File(configBase, "secmod.db"); + if (secmodFile.isFile() == false) { + throw new FileNotFoundException(secmodFile.getPath()); + } + } + } + + if (DEBUG) System.out.println("lib: " + platformPath); + nssHandle = nssLoadLibrary(platformPath); + if (DEBUG) System.out.println("handle: " + nssHandle); + fetchVersions(); + if (supported == false) { + throw new IOException + ("The specified version of NSS is incompatible, " + + "3.7 or later required"); + } + + if (DEBUG) System.out.println("dir: " + configDir); + boolean initok = nssInitialize(dbMode.functionName, nssHandle, + configDir, nssOptimizeSpace); + if (DEBUG) System.out.println("init: " + initok); + if (initok == false) { + throw new IOException("NSS initialization failed"); + } + + this.configDir = configDir; + this.nssLibDir = nssLibDir; + } + + /** + * Return an immutable list of all available modules. + * + * @throws IllegalStateException if this Secmod is misconfigured + * or not initialized + */ + public synchronized List getModules() { + try { + if (isInitialized() == false) { + throw new IllegalStateException("NSS not initialized"); + } + } catch (IOException e) { + // IOException if misconfigured + throw new IllegalStateException(e); + } + if (modules == null) { + @SuppressWarnings("unchecked") + List modules = (List)nssGetModuleList(nssHandle, + nssLibDir); + this.modules = Collections.unmodifiableList(modules); + } + return modules; + } + + private static byte[] getDigest(X509Certificate cert, String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + return md.digest(cert.getEncoded()); + } catch (GeneralSecurityException e) { + throw new ProviderException(e); + } + } + + boolean isTrusted(X509Certificate cert, TrustType trustType) { + Bytes bytes = new Bytes(getDigest(cert, "SHA-1")); + TrustAttributes attr = getModuleTrust(ModuleType.KEYSTORE, bytes); + if (attr == null) { + attr = getModuleTrust(ModuleType.FIPS, bytes); + if (attr == null) { + attr = getModuleTrust(ModuleType.TRUSTANCHOR, bytes); + } + } + return (attr == null) ? false : attr.isTrusted(trustType); + } + + private TrustAttributes getModuleTrust(ModuleType type, Bytes bytes) { + Module module = getModule(type); + TrustAttributes t = (module == null) ? null : module.getTrust(bytes); + return t; + } + + /** + * Constants describing the different types of NSS modules. + * For this API, NSS modules are classified as either one + * of the internal modules delivered as part of NSS or + * as an external module provided by a 3rd party. + */ + public static enum ModuleType { + /** + * The NSS Softtoken crypto module. This is the first + * slot of the softtoken object. + * This module provides + * implementations for cryptographic algorithms but no KeyStore. + */ + CRYPTO, + /** + * The NSS Softtoken KeyStore module. This is the second + * slot of the softtoken object. + * This module provides + * implementations for cryptographic algorithms (after login) + * and the KeyStore. + */ + KEYSTORE, + /** + * The NSS Softtoken module in FIPS mode. Note that in FIPS mode the + * softtoken presents only one slot, not separate CRYPTO and KEYSTORE + * slots as in non-FIPS mode. + */ + FIPS, + /** + * The NSS builtin trust anchor module. This is the + * NSSCKBI object. It provides no crypto functions. + */ + TRUSTANCHOR, + /** + * An external module. + */ + EXTERNAL, + } + + /** + * Returns the first module of the specified type. If no such + * module exists, this method returns null. + * + * @throws IllegalStateException if this Secmod is misconfigured + * or not initialized + */ + public Module getModule(ModuleType type) { + for (Module module : getModules()) { + if (module.getType() == type) { + return module; + } + } + return null; + } + + static final String TEMPLATE_EXTERNAL = + "library = %s\n" + + "name = \"%s\"\n" + + "slotListIndex = %d\n"; + + static final String TEMPLATE_TRUSTANCHOR = + "library = %s\n" + + "name = \"NSS Trust Anchors\"\n" + + "slotListIndex = 0\n" + + "enabledMechanisms = { KeyStore }\n" + + "nssUseSecmodTrust = true\n"; + + static final String TEMPLATE_CRYPTO = + "library = %s\n" + + "name = \"NSS SoftToken Crypto\"\n" + + "slotListIndex = 0\n" + + "disabledMechanisms = { KeyStore }\n"; + + static final String TEMPLATE_KEYSTORE = + "library = %s\n" + + "name = \"NSS SoftToken KeyStore\"\n" + + "slotListIndex = 1\n" + + "nssUseSecmodTrust = true\n"; + + static final String TEMPLATE_FIPS = + "library = %s\n" + + "name = \"NSS FIPS SoftToken\"\n" + + "slotListIndex = 0\n" + + "nssUseSecmodTrust = true\n"; + + /** + * A representation of one PKCS#11 slot in a PKCS#11 module. + */ + public static final class Module { + // path of the native library + final String libraryName; + // descriptive name used by NSS + final String commonName; + final int slot; + final ModuleType type; + + private String config; + private SunPKCS11 provider; + + // trust attributes. Used for the KEYSTORE and TRUSTANCHOR modules only + private Map trust; + + Module(String libraryDir, String libraryName, String commonName, + int slotIndex, int slotId) { + ModuleType type; + + if ((libraryName == null) || (libraryName.length() == 0)) { + // must be softtoken + libraryName = System.mapLibraryName(SOFTTOKEN_LIB_NAME); + if (slotId == NETSCAPE_SLOT_ID) { + type = ModuleType.CRYPTO; + } else if (slotId == PRIVATE_KEY_SLOT_ID) { + type = ModuleType.KEYSTORE; + } else if (slotId == FIPS_SLOT_ID) { + type = ModuleType.FIPS; + } else { + throw new RuntimeException("Unexpected slot ID " + slotId + + " in the NSS Internal Module"); + } + } else { + if (libraryName.endsWith(System.mapLibraryName(TRUST_LIB_NAME)) + || commonName.equals("Builtin Roots Module")) { + type = ModuleType.TRUSTANCHOR; + } else { + type = ModuleType.EXTERNAL; + } + } + // On Ubuntu the libsoftokn3 library is located in a subdirectory + // of the system libraries directory. (Since Ubuntu 11.04.) + File libraryFile = new File(libraryDir, libraryName); + if (!libraryFile.isFile()) { + File failover = new File(libraryDir, "nss/" + libraryName); + if (failover.isFile()) { + libraryFile = failover; + } + } + this.libraryName = libraryFile.getPath(); + this.commonName = commonName; + this.slot = slotIndex; + this.type = type; + initConfiguration(); + } + + private void initConfiguration() { + switch (type) { + case EXTERNAL: + config = String.format(TEMPLATE_EXTERNAL, libraryName, + commonName + " " + slot, slot); + break; + case CRYPTO: + config = String.format(TEMPLATE_CRYPTO, libraryName); + break; + case KEYSTORE: + config = String.format(TEMPLATE_KEYSTORE, libraryName); + break; + case FIPS: + config = String.format(TEMPLATE_FIPS, libraryName); + break; + case TRUSTANCHOR: + config = String.format(TEMPLATE_TRUSTANCHOR, libraryName); + break; + default: + throw new RuntimeException("Unknown module type: " + type); + } + } + + /** + * Get the configuration for this module. This is a string + * in the SunPKCS11 configuration format. It can be + * customized with additional options and then made + * current using the setConfiguration() method. + */ + @Deprecated + public synchronized String getConfiguration() { + return config; + } + + /** + * Set the configuration for this module. + * + * @throws IllegalStateException if the associated provider + * instance has already been created. + */ + @Deprecated + public synchronized void setConfiguration(String config) { + if (provider != null) { + throw new IllegalStateException("Provider instance already created"); + } + this.config = config; + } + + /** + * Return the pathname of the native library that implements + * this module. For example, /usr/lib/libpkcs11.so. + */ + public String getLibraryName() { + return libraryName; + } + + /** + * Returns the type of this module. + */ + public ModuleType getType() { + return type; + } + + /** + * Returns the provider instance that is associated with this + * module. The first call to this method creates the provider + * instance. + */ + @Deprecated + public synchronized Provider getProvider() { + if (provider == null) { + provider = newProvider(); + } + return provider; + } + + synchronized boolean hasInitializedProvider() { + return provider != null; + } + + void setProvider(SunPKCS11 p) { + if (provider != null) { + throw new ProviderException("Secmod provider already initialized"); + } + provider = p; + } + + private SunPKCS11 newProvider() { + try { + InputStream in = new ByteArrayInputStream(config.getBytes("UTF8")); + return new SunPKCS11(in); + } catch (Exception e) { + // XXX + throw new ProviderException(e); + } + } + + synchronized void setTrust(Token token, X509Certificate cert) { + Bytes bytes = new Bytes(getDigest(cert, "SHA-1")); + TrustAttributes attr = getTrust(bytes); + if (attr == null) { + attr = new TrustAttributes(token, cert, bytes, CKT_NETSCAPE_TRUSTED_DELEGATOR); + trust.put(bytes, attr); + } else { + // does it already have the correct trust settings? + if (attr.isTrusted(TrustType.ALL) == false) { + // XXX not yet implemented + throw new ProviderException("Cannot change existing trust attributes"); + } + } + } + + TrustAttributes getTrust(Bytes hash) { + if (trust == null) { + // If provider is not set, create a temporary provider to + // retrieve the trust information. This can happen if we need + // to get the trust information for the trustanchor module + // because we need to look for user customized settings in the + // keystore module (which may not have a provider created yet). + // Creating a temporary provider and then dropping it on the + // floor immediately is flawed, but it's the best we can do + // for now. + synchronized (this) { + SunPKCS11 p = provider; + if (p == null) { + p = newProvider(); + } + try { + trust = Secmod.getTrust(p); + } catch (PKCS11Exception e) { + throw new RuntimeException(e); + } + } + } + return trust.get(hash); + } + + public String toString() { + return + commonName + " (" + type + ", " + libraryName + ", slot " + slot + ")"; + } + + } + + /** + * Constants representing NSS trust categories. + */ + public static enum TrustType { + /** Trusted for all purposes */ + ALL, + /** Trusted for SSL client authentication */ + CLIENT_AUTH, + /** Trusted for SSL server authentication */ + SERVER_AUTH, + /** Trusted for code signing */ + CODE_SIGNING, + /** Trusted for email protection */ + EMAIL_PROTECTION, + } + + public static enum DbMode { + READ_WRITE("NSS_InitReadWrite"), + READ_ONLY ("NSS_Init"), + NO_DB ("NSS_NoDB_Init"); + + final String functionName; + DbMode(String functionName) { + this.functionName = functionName; + } + } + + /** + * A LoadStoreParameter for use with the NSS Softtoken or + * NSS TrustAnchor KeyStores. + *

+ * It allows the set of trusted certificates that are returned by + * the KeyStore to be specified. + */ + public static final class KeyStoreLoadParameter implements LoadStoreParameter { + final TrustType trustType; + final ProtectionParameter protection; + public KeyStoreLoadParameter(TrustType trustType, char[] password) { + this(trustType, new PasswordProtection(password)); + + } + public KeyStoreLoadParameter(TrustType trustType, ProtectionParameter prot) { + if (trustType == null) { + throw new NullPointerException("trustType must not be null"); + } + this.trustType = trustType; + this.protection = prot; + } + public ProtectionParameter getProtectionParameter() { + return protection; + } + public TrustType getTrustType() { + return trustType; + } + } + + static class TrustAttributes { + final long handle; + final long clientAuth, serverAuth, codeSigning, emailProtection; + final byte[] shaHash; + TrustAttributes(Token token, X509Certificate cert, Bytes bytes, long trustValue) { + Session session = null; + try { + session = token.getOpSession(); + // XXX use KeyStore TrustType settings to determine which + // attributes to set + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_TOKEN, true), + new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST), + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH, trustValue), + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING, trustValue), + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION, trustValue), + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH, trustValue), + new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH, bytes.b), + new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_MD5_HASH, getDigest(cert, "MD5")), + new CK_ATTRIBUTE(CKA_ISSUER, cert.getIssuerX500Principal().getEncoded()), + new CK_ATTRIBUTE(CKA_SERIAL_NUMBER, cert.getSerialNumber().toByteArray()), + // XXX per PKCS#11 spec, the serial number should be in ASN.1 + }; + handle = token.p11.C_CreateObject(session.id(), attrs); + shaHash = bytes.b; + clientAuth = trustValue; + serverAuth = trustValue; + codeSigning = trustValue; + emailProtection = trustValue; + } catch (PKCS11Exception e) { + throw new ProviderException("Could not create trust object", e); + } finally { + token.releaseSession(session); + } + } + TrustAttributes(Token token, Session session, long handle) + throws PKCS11Exception { + this.handle = handle; + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH), + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING), + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION), + new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH), + }; + + token.p11.C_GetAttributeValue(session.id(), handle, attrs); + serverAuth = attrs[0].getLong(); + codeSigning = attrs[1].getLong(); + emailProtection = attrs[2].getLong(); + shaHash = attrs[3].getByteArray(); + + attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH), + }; + long c; + try { + token.p11.C_GetAttributeValue(session.id(), handle, attrs); + c = attrs[0].getLong(); + } catch (PKCS11Exception e) { + // trust anchor module does not support this attribute + c = serverAuth; + } + clientAuth = c; + } + Bytes getHash() { + return new Bytes(shaHash); + } + boolean isTrusted(TrustType type) { + switch (type) { + case CLIENT_AUTH: + return isTrusted(clientAuth); + case SERVER_AUTH: + return isTrusted(serverAuth); + case CODE_SIGNING: + return isTrusted(codeSigning); + case EMAIL_PROTECTION: + return isTrusted(emailProtection); + case ALL: + return isTrusted(TrustType.CLIENT_AUTH) + && isTrusted(TrustType.SERVER_AUTH) + && isTrusted(TrustType.CODE_SIGNING) + && isTrusted(TrustType.EMAIL_PROTECTION); + default: + return false; + } + } + + private boolean isTrusted(long l) { + // XXX CKT_TRUSTED? + return (l == CKT_NETSCAPE_TRUSTED_DELEGATOR); + } + + } + + private static class Bytes { + final byte[] b; + Bytes(byte[] b) { + this.b = b; + } + public int hashCode() { + return Arrays.hashCode(b); + } + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof Bytes == false) { + return false; + } + Bytes other = (Bytes)o; + return Arrays.equals(this.b, other.b); + } + } + + private static Map getTrust(SunPKCS11 provider) + throws PKCS11Exception { + Map trustMap = new HashMap(); + Token token = provider.getToken(); + Session session = null; + try { + session = token.getOpSession(); + int MAX_NUM = 8192; + CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST), + }; + token.p11.C_FindObjectsInit(session.id(), attrs); + long[] handles = token.p11.C_FindObjects(session.id(), MAX_NUM); + token.p11.C_FindObjectsFinal(session.id()); + if (DEBUG) System.out.println("handles: " + handles.length); + + for (long handle : handles) { + try { + TrustAttributes trust = new TrustAttributes(token, session, handle); + trustMap.put(trust.getHash(), trust); + } catch (PKCS11Exception e) { + // skip put on pkcs11 error + } + } + } finally { + token.releaseSession(session); + } + return trustMap; + } + + private static native long nssGetLibraryHandle(String libraryName); + + private static native long nssLoadLibrary(String name) throws IOException; + + private static native boolean nssVersionCheck(long handle, String minVersion); + + private static native boolean nssInitialize(String functionName, long handle, String configDir, boolean nssOptimizeSpace); + + private static native Object nssGetModuleList(long handle, String libDir); + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/Session.java b/src/main/java/com/sunyard/security/pkcs11/Session.java new file mode 100644 index 0000000..670b0a4 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/Session.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.lang.ref.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +import java.security.*; + +import com.sunyard.security.pkcs11.wrapper.*; + +/** + * A session object. Sessions are obtained via the SessionManager, + * see there for details. Most code will only ever need one method in + * this class, the id() method to obtain the session id. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class Session implements Comparable { + + // time after which to close idle sessions, in milliseconds (3 minutes) + private final static long MAX_IDLE_TIME = 3 * 60 * 1000; + + // token instance + final Token token; + + // session id + private final long id; + + // number of objects created within this session + private final AtomicInteger createdObjects; + + // time this session was last used + // not synchronized/volatile for performance, so may be unreliable + // this could lead to idle sessions being closed early, but that is harmless + private long lastAccess; + + private final SessionRef sessionRef; + + Session(Token token, long id) { + this.token = token; + this.id = id; + createdObjects = new AtomicInteger(); + id(); + sessionRef = new SessionRef(this, id, token); + } + + public int compareTo(Session other) { + if (this.lastAccess == other.lastAccess) { + return 0; + } else { + return (this.lastAccess < other.lastAccess) ? -1 : 1; + } + } + + boolean isLive(long currentTime) { + return currentTime - lastAccess < MAX_IDLE_TIME; + } + + long idInternal() { + return id; + } + + long id() { + if (token.isPresent(this.id) == false) { + throw new ProviderException("Token has been removed"); + } + lastAccess = System.currentTimeMillis(); + return id; + } + + void addObject() { + int n = createdObjects.incrementAndGet(); + // XXX update statistics in session manager if n == 1 + } + + void removeObject() { + int n = createdObjects.decrementAndGet(); + if (n == 0) { + token.sessionManager.demoteObjSession(this); + } else if (n < 0) { + throw new ProviderException("Internal error: objects created " + n); + } + } + + boolean hasObjects() { + return createdObjects.get() != 0; + } + + void close() { + if (hasObjects()) { + throw new ProviderException( + "Internal error: close session with active objects"); + } + sessionRef.dispose(); + } +} + +/* + * NOTE: Use PhantomReference here and not WeakReference + * otherwise the sessions maybe closed before other objects + * which are still being finalized. + */ +final class SessionRef extends PhantomReference + implements Comparable { + + private static ReferenceQueue refQueue = + new ReferenceQueue(); + + private static Set refList = + Collections.synchronizedSortedSet(new TreeSet()); + + static ReferenceQueue referenceQueue() { + return refQueue; + } + + static int totalCount() { + return refList.size(); + } + + private static void drainRefQueueBounded() { + while (true) { + SessionRef next = (SessionRef) refQueue.poll(); + if (next == null) break; + next.dispose(); + } + } + + // handle to the native session + private long id; + private Token token; + + SessionRef(Session session, long id, Token token) { + super(session, refQueue); + this.id = id; + this.token = token; + refList.add(this); + // TBD: run at some interval and not every time? + drainRefQueueBounded(); + } + + void dispose() { + refList.remove(this); + try { + if (token.isPresent(id)) { + token.p11.C_CloseSession(id); + } + } catch (PKCS11Exception e1) { + // ignore + } catch (ProviderException e2) { + // ignore + } finally { + this.clear(); + } + } + + public int compareTo(SessionRef other) { + if (this.id == other.id) { + return 0; + } else { + return (this.id < other.id) ? -1 : 1; + } + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/SessionManager.java b/src/main/java/com/sunyard/security/pkcs11/SessionManager.java new file mode 100644 index 0000000..da21863 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/SessionManager.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; + +import java.security.ProviderException; + +import sun.security.util.Debug; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Session manager. There is one session manager object per PKCS#11 + * provider. It allows code to checkout a session, release it + * back to the pool, or force it to be closed. + * + * The session manager pools sessions to minimize the number of + * C_OpenSession() and C_CloseSession() that have to be made. It + * maintains two pools: one for "object" sessions and one for + * "operation" sessions. + * + * The reason for this separation is how PKCS#11 deals with session objects. + * It defines that when a session is closed, all objects created within + * that session are destroyed. In other words, we may never close a session + * while a Key created it in is still in use. We would like to keep the + * number of such sessions low. Note that we occasionally want to explicitly + * close a session, see P11Signature. + * + * NOTE that sessions obtained from this class SHOULD be returned using + * either releaseSession() or closeSession() using a finally block when + * not needed anymore. Otherwise, they will be left for cleanup via the + * PhantomReference mechanism when GC kicks in, but it's best not to rely + * on that since GC may not run timely enough since the native PKCS11 library + * is also consuming memory. + * + * Note that sessions are automatically closed when they are not used for a + * period of time, see Session. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class SessionManager { + + private final static int DEFAULT_MAX_SESSIONS = 32; + + private final static Debug debug = Debug.getInstance("pkcs11"); + + // token instance + private final Token token; + + // maximum number of sessions to open with this token + private final int maxSessions; + + // total number of active sessions + private AtomicInteger activeSessions = new AtomicInteger(); + + // pool of available object sessions + private final Pool objSessions; + + // pool of available operation sessions + private final Pool opSessions; + + // maximum number of active sessions during this invocation, for debugging + private int maxActiveSessions; + private Object maxActiveSessionsLock; + + // flags to use in the C_OpenSession() call + private final long openSessionFlags; + + SessionManager(Token token) { + long n; + if (token.isWriteProtected()) { + openSessionFlags = CKF_SERIAL_SESSION; + n = token.tokenInfo.ulMaxSessionCount; + } else { + openSessionFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + n = token.tokenInfo.ulMaxRwSessionCount; + } + if (n == CK_EFFECTIVELY_INFINITE) { + n = Integer.MAX_VALUE; + } else if ((n == CK_UNAVAILABLE_INFORMATION) || (n < 0)) { + // choose an arbitrary concrete value + n = DEFAULT_MAX_SESSIONS; + } + maxSessions = (int)Math.min(n, Integer.MAX_VALUE); + this.token = token; + this.objSessions = new Pool(this); + this.opSessions = new Pool(this); + if (debug != null) { + maxActiveSessionsLock = new Object(); + } + } + + // returns whether only a fairly low number of sessions are + // supported by this token. + boolean lowMaxSessions() { + return (maxSessions <= DEFAULT_MAX_SESSIONS); + } + + Session getObjSession() throws PKCS11Exception { + Session session = objSessions.poll(); + if (session != null) { + return ensureValid(session); + } + session = opSessions.poll(); + if (session != null) { + return ensureValid(session); + } + session = openSession(); + return ensureValid(session); + } + + Session getOpSession() throws PKCS11Exception { + Session session = opSessions.poll(); + if (session != null) { + return ensureValid(session); + } + // create a new session rather than re-using an obj session + // that avoids potential expensive cancels() for Signatures & RSACipher + if (maxSessions == Integer.MAX_VALUE || + activeSessions.get() < maxSessions) { + session = openSession(); + return ensureValid(session); + } + session = objSessions.poll(); + if (session != null) { + return ensureValid(session); + } + throw new ProviderException("Could not obtain session"); + } + + private Session ensureValid(Session session) { + session.id(); + return session; + } + + Session killSession(Session session) { + if ((session == null) || (token.isValid() == false)) { + return null; + } + if (debug != null) { + String location = new Exception().getStackTrace()[2].toString(); + System.out.println("Killing session (" + location + ") active: " + + activeSessions.get()); + } + closeSession(session); + return null; + } + + Session releaseSession(Session session) { + if ((session == null) || (token.isValid() == false)) { + return null; + } + + if (session.hasObjects()) { + objSessions.release(session); + } else { + opSessions.release(session); + } + return null; + } + + void demoteObjSession(Session session) { + if (token.isValid() == false) { + return; + } + if (debug != null) { + System.out.println("Demoting session, active: " + + activeSessions.get()); + } + boolean present = objSessions.remove(session); + if (present == false) { + // session is currently in use + // will be added to correct pool on release, nothing to do now + return; + } + // Objects could have been added to this session by other thread between + // check in Session.removeObject method and objSessions.remove call + // higher. Therefore releaseSession method, which performs additional + // check for objects, is used here to avoid placing this session + // in wrong pool due to race condition. + releaseSession(session); + } + + private Session openSession() throws PKCS11Exception { + if ((maxSessions != Integer.MAX_VALUE) && + (activeSessions.get() >= maxSessions)) { + throw new ProviderException("No more sessions available"); + } + + long id = token.p11.C_OpenSession + (token.provider.slotID, openSessionFlags, null, null); + Session session = new Session(token, id); + activeSessions.incrementAndGet(); + if (debug != null) { + synchronized(maxActiveSessionsLock) { + if (activeSessions.get() > maxActiveSessions) { + maxActiveSessions = activeSessions.get(); + if (maxActiveSessions % 10 == 0) { + System.out.println("Open sessions: " + maxActiveSessions); + } + } + } + } + return session; + } + + private void closeSession(Session session) { + session.close(); + activeSessions.decrementAndGet(); + } + + public static final class Pool { + + private final SessionManager mgr; + + private final ConcurrentLinkedDeque pool; + + Pool(SessionManager mgr) { + this.mgr = mgr; + pool = new ConcurrentLinkedDeque(); + } + + boolean remove(Session session) { + return pool.remove(session); + } + + Session poll() { + return pool.pollLast(); + } + + void release(Session session) { + pool.offer(session); + if (session.hasObjects()) { + return; + } + + int n = pool.size(); + if (n < 5) { + return; + } + + Session oldestSession; + long time = System.currentTimeMillis(); + int i = 0; + // Check if the session head is too old and continue through queue + // until only one is left. + do { + oldestSession = pool.peek(); + if (oldestSession == null || oldestSession.isLive(time) || + !pool.remove(oldestSession)) { + break; + } + + i++; + mgr.closeSession(oldestSession); + } while ((n - i) > 1); + + if (debug != null) { + System.out.println("Closing " + i + " idle sessions, active: " + + mgr.activeSessions); + } + } + + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/SunPKCS11.java b/src/main/java/com/sunyard/security/pkcs11/SunPKCS11.java new file mode 100644 index 0000000..9092990 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/SunPKCS11.java @@ -0,0 +1,1550 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.io.*; +import java.util.*; + +import java.security.*; +import java.security.interfaces.*; + +import javax.crypto.interfaces.*; + +import javax.security.auth.Subject; +import javax.security.auth.login.LoginException; +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextOutputCallback; + +import sun.security.util.Debug; +import sun.security.util.ResourcesMgr; + +import com.sunyard.security.pkcs11.Secmod.*; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * PKCS#11 provider main class. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +public final class SunPKCS11 extends AuthProvider { + + private static final long serialVersionUID = -1354835039035306505L; + + static final Debug debug = Debug.getInstance("sunpkcs11"); + + private static int dummyConfigId; + + // the PKCS11 object through which we make the native calls + final PKCS11 p11; + + // name of the configuration file + private final String configName; + + // configuration information + final Config config; + + // id of the PKCS#11 slot we are using + final long slotID; + + private CallbackHandler pHandler; + private final Object LOCK_HANDLER = new Object(); + + final boolean removable; + + final Module nssModule; + + final boolean nssUseSecmodTrust; + + private volatile Token token; + + private TokenPoller poller; + + Token getToken() { + return token; + } + + public SunPKCS11() { + super("SunPKCS11-Dummy", 1.8d, "SunPKCS11-Dummy"); + throw new ProviderException + ("SunPKCS11 requires configuration file argument"); + } + + public SunPKCS11(String configName) { + this(checkNull(configName), null); + } + + public SunPKCS11(InputStream configStream) { + this(getDummyConfigName(), checkNull(configStream)); + } + + private static T checkNull(T obj) { + if (obj == null) { + throw new NullPointerException(); + } + return obj; + } + + private static synchronized String getDummyConfigName() { + int id = ++dummyConfigId; + return "---DummyConfig-" + id + "---"; + } + + /** + * @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream) + * instead + */ + @Deprecated + public SunPKCS11(String configName, InputStream configStream) { + super("SunPKCS11-" + + Config.getConfig(configName, configStream).getName(), + 1.8d, Config.getConfig(configName, configStream).getDescription()); + this.configName = configName; + this.config = Config.removeConfig(configName); + + if (debug != null) { + System.out.println("SunPKCS11 loading " + configName); + } + + String library = config.getLibrary(); + String functionList = config.getFunctionList(); + long slotID = config.getSlotID(); + int slotListIndex = config.getSlotListIndex(); + + boolean useSecmod = config.getNssUseSecmod(); + boolean nssUseSecmodTrust = config.getNssUseSecmodTrust(); + Module nssModule = null; + + // + // Initialization via Secmod. The way this works is as follows: + // SunPKCS11 is either in normal mode or in NSS Secmod mode. + // Secmod is activated by specifying one or more of the following + // options in the config file: + // nssUseSecmod, nssSecmodDirectory, nssLibrary, nssModule + // + // XXX add more explanation here + // + // If we are in Secmod mode and configured to use either the + // nssKeyStore or the nssTrustAnchors module, we automatically + // switch to using the NSS trust attributes for trusted certs + // (KeyStore). + // + + if (useSecmod) { + // note: Config ensures library/slot/slotListIndex not specified + // in secmod mode. + Secmod secmod = Secmod.getInstance(); + DbMode nssDbMode = config.getNssDbMode(); + try { + String nssLibraryDirectory = config.getNssLibraryDirectory(); + String nssSecmodDirectory = config.getNssSecmodDirectory(); + boolean nssOptimizeSpace = config.getNssOptimizeSpace(); + + if (secmod.isInitialized()) { + if (nssSecmodDirectory != null) { + String s = secmod.getConfigDir(); + if ((s != null) && + (s.equals(nssSecmodDirectory) == false)) { + throw new ProviderException("Secmod directory " + + nssSecmodDirectory + + " invalid, NSS already initialized with " + + s); + } + } + if (nssLibraryDirectory != null) { + String s = secmod.getLibDir(); + if ((s != null) && + (s.equals(nssLibraryDirectory) == false)) { + throw new ProviderException("NSS library directory " + + nssLibraryDirectory + + " invalid, NSS already initialized with " + + s); + } + } + } else { + if (nssDbMode != DbMode.NO_DB) { + if (nssSecmodDirectory == null) { + throw new ProviderException( + "Secmod not initialized and " + + "nssSecmodDirectory not specified"); + } + } else { + if (nssSecmodDirectory != null) { + throw new ProviderException( + "nssSecmodDirectory must not be " + + "specified in noDb mode"); + } + } + secmod.initialize(nssDbMode, nssSecmodDirectory, + nssLibraryDirectory, nssOptimizeSpace); + } + } catch (IOException e) { + // XXX which exception to throw + throw new ProviderException("Could not initialize NSS", e); + } + List modules = secmod.getModules(); + if (config.getShowInfo()) { + System.out.println("NSS modules: " + modules); + } + + String moduleName = config.getNssModule(); + if (moduleName == null) { + nssModule = secmod.getModule(ModuleType.FIPS); + if (nssModule != null) { + moduleName = "fips"; + } else { + moduleName = (nssDbMode == DbMode.NO_DB) ? + "crypto" : "keystore"; + } + } + if (moduleName.equals("fips")) { + nssModule = secmod.getModule(ModuleType.FIPS); + nssUseSecmodTrust = true; + functionList = "FC_GetFunctionList"; + } else if (moduleName.equals("keystore")) { + nssModule = secmod.getModule(ModuleType.KEYSTORE); + nssUseSecmodTrust = true; + } else if (moduleName.equals("crypto")) { + nssModule = secmod.getModule(ModuleType.CRYPTO); + } else if (moduleName.equals("trustanchors")) { + // XXX should the option be called trustanchor or trustanchors?? + nssModule = secmod.getModule(ModuleType.TRUSTANCHOR); + nssUseSecmodTrust = true; + } else if (moduleName.startsWith("external-")) { + int moduleIndex; + try { + moduleIndex = Integer.parseInt + (moduleName.substring("external-".length())); + } catch (NumberFormatException e) { + moduleIndex = -1; + } + if (moduleIndex < 1) { + throw new ProviderException + ("Invalid external module: " + moduleName); + } + int k = 0; + for (Module module : modules) { + if (module.getType() == ModuleType.EXTERNAL) { + if (++k == moduleIndex) { + nssModule = module; + break; + } + } + } + if (nssModule == null) { + throw new ProviderException("Invalid module " + moduleName + + ": only " + k + " external NSS modules available"); + } + } else { + throw new ProviderException( + "Unknown NSS module: " + moduleName); + } + if (nssModule == null) { + throw new ProviderException( + "NSS module not available: " + moduleName); + } + if (nssModule.hasInitializedProvider()) { + throw new ProviderException("Secmod module already configured"); + } + library = nssModule.libraryName; + slotListIndex = nssModule.slot; + } + this.nssUseSecmodTrust = nssUseSecmodTrust; + this.nssModule = nssModule; + + File libraryFile = new File(library); + // if the filename is a simple filename without path + // (e.g. "libpkcs11.so"), it may refer to a library somewhere on the + // OS library search path. Omit the test for file existance as that + // only looks in the current directory. + if (libraryFile.getName().equals(library) == false) { + if (new File(library).isFile() == false) { + String msg = "Library " + library + " does not exist"; + if (config.getHandleStartupErrors() == Config.ERR_HALT) { + throw new ProviderException(msg); + } else { + throw new UnsupportedOperationException(msg); + } + } + } + + try { + if (debug != null) { + debug.println("Initializing PKCS#11 library " + library); + } + CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS(); + String nssArgs = config.getNssArgs(); + if (nssArgs != null) { + initArgs.pReserved = nssArgs; + } + // request multithreaded access first + initArgs.flags = CKF_OS_LOCKING_OK; + PKCS11 tmpPKCS11; + try { + tmpPKCS11 = PKCS11.getInstance( + library, functionList, initArgs, + config.getOmitInitialize()); + } catch (PKCS11Exception e) { + if (debug != null) { + debug.println("Multi-threaded initialization failed: " + e); + } + if (config.getAllowSingleThreadedModules() == false) { + throw e; + } + // fall back to single threaded access + if (nssArgs == null) { + // if possible, use null initArgs for better compatibility + initArgs = null; + } else { + initArgs.flags = 0; + } + tmpPKCS11 = PKCS11.getInstance(library, + functionList, initArgs, config.getOmitInitialize()); + } + p11 = tmpPKCS11; + + CK_INFO p11Info = p11.C_GetInfo(); + if (p11Info.cryptokiVersion.major < 2) { + throw new ProviderException("Only PKCS#11 v2.0 and later " + + "supported, library version is v" + p11Info.cryptokiVersion); + } + boolean showInfo = config.getShowInfo(); + if (showInfo) { + System.out.println("Information for provider " + getName()); + System.out.println("Library info:"); + System.out.println(p11Info); + } + + if ((slotID < 0) || showInfo) { + long[] slots = p11.C_GetSlotList(false); + if (showInfo) { + System.out.println("All slots: " + toString(slots)); + slots = p11.C_GetSlotList(true); + System.out.println("Slots with tokens: " + toString(slots)); + } + if (slotID < 0) { + if ((slotListIndex < 0) + || (slotListIndex >= slots.length)) { + throw new ProviderException("slotListIndex is " + + slotListIndex + + " but token only has " + slots.length + " slots"); + } + slotID = slots[slotListIndex]; + } + } + this.slotID = slotID; + CK_SLOT_INFO slotInfo = p11.C_GetSlotInfo(slotID); + removable = (slotInfo.flags & CKF_REMOVABLE_DEVICE) != 0; + initToken(slotInfo); + if (nssModule != null) { + nssModule.setProvider(this); + } + } catch (Exception e) { + if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) { + throw new UnsupportedOperationException + ("Initialization failed", e); + } else { + throw new ProviderException + ("Initialization failed", e); + } + } + } + + private static String toString(long[] longs) { + if (longs.length == 0) { + return "(none)"; + } + StringBuilder sb = new StringBuilder(); + sb.append(longs[0]); + for (int i = 1; i < longs.length; i++) { + sb.append(", "); + sb.append(longs[i]); + } + return sb.toString(); + } + + public boolean equals(Object obj) { + return this == obj; + } + + public int hashCode() { + return System.identityHashCode(this); + } + + private static String[] s(String ...aliases) { + return aliases; + } + + private static final class Descriptor { + final String type; + final String algorithm; + final String className; + final String[] aliases; + final int[] mechanisms; + + private Descriptor(String type, String algorithm, String className, + String[] aliases, int[] mechanisms) { + this.type = type; + this.algorithm = algorithm; + this.className = className; + this.aliases = aliases; + this.mechanisms = mechanisms; + } + private P11Service service(Token token, int mechanism) { + return new P11Service + (token, type, algorithm, className, aliases, mechanism); + } + public String toString() { + return type + "." + algorithm; + } + } + + // Map from mechanism to List of Descriptors that should be + // registered if the mechanism is supported + private final static Map> descriptors = + new HashMap>(); + + private static int[] m(long m1) { + return new int[] {(int)m1}; + } + + private static int[] m(long m1, long m2) { + return new int[] {(int)m1, (int)m2}; + } + + private static int[] m(long m1, long m2, long m3) { + return new int[] {(int)m1, (int)m2, (int)m3}; + } + + private static int[] m(long m1, long m2, long m3, long m4) { + return new int[] {(int)m1, (int)m2, (int)m3, (int)m4}; + } + + private static void d(String type, String algorithm, String className, + int[] m) { + register(new Descriptor(type, algorithm, className, null, m)); + } + + private static void d(String type, String algorithm, String className, + String[] aliases, int[] m) { + register(new Descriptor(type, algorithm, className, aliases, m)); + } + + private static void register(Descriptor d) { + for (int i = 0; i < d.mechanisms.length; i++) { + int m = d.mechanisms[i]; + Integer key = Integer.valueOf(m); + List list = descriptors.get(key); + if (list == null) { + list = new ArrayList(); + descriptors.put(key, list); + } + list.add(d); + } + } + + private final static String MD = "MessageDigest"; + + private final static String SIG = "Signature"; + + private final static String KPG = "KeyPairGenerator"; + + private final static String KG = "KeyGenerator"; + + private final static String AGP = "AlgorithmParameters"; + + private final static String KF = "KeyFactory"; + + private final static String SKF = "SecretKeyFactory"; + + private final static String CIP = "Cipher"; + + private final static String MAC = "Mac"; + + private final static String KA = "KeyAgreement"; + + private final static String KS = "KeyStore"; + + private final static String SR = "SecureRandom"; + + static { + // names of all the implementation classes + // use local variables, only used here + String P11Digest = "sun.security.pkcs11.P11Digest"; + String P11MAC = "sun.security.pkcs11.P11MAC"; + String P11KeyPairGenerator = "sun.security.pkcs11.P11KeyPairGenerator"; + String P11KeyGenerator = "sun.security.pkcs11.P11KeyGenerator"; + String P11RSAKeyFactory = "sun.security.pkcs11.P11RSAKeyFactory"; + String P11DSAKeyFactory = "sun.security.pkcs11.P11DSAKeyFactory"; + String P11DHKeyFactory = "sun.security.pkcs11.P11DHKeyFactory"; + String P11KeyAgreement = "sun.security.pkcs11.P11KeyAgreement"; + String P11SecretKeyFactory = "sun.security.pkcs11.P11SecretKeyFactory"; + String P11Cipher = "sun.security.pkcs11.P11Cipher"; + String P11RSACipher = "sun.security.pkcs11.P11RSACipher"; + String P11AEADCipher = "sun.security.pkcs11.P11AEADCipher"; + String P11Signature = "sun.security.pkcs11.P11Signature"; + String P11PSSSignature = "sun.security.pkcs11.P11PSSSignature"; + + // XXX register all aliases + + d(MD, "MD2", P11Digest, + m(CKM_MD2)); + d(MD, "MD5", P11Digest, + m(CKM_MD5)); + d(MD, "SHA1", P11Digest, + s("SHA", "SHA-1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"), + m(CKM_SHA_1)); + + d(MD, "SHA-224", P11Digest, + s("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"), + m(CKM_SHA224)); + d(MD, "SHA-256", P11Digest, + s("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"), + m(CKM_SHA256)); + d(MD, "SHA-384", P11Digest, + s("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"), + m(CKM_SHA384)); + d(MD, "SHA-512", P11Digest, + s("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"), + m(CKM_SHA512)); + d(MD, "SHA-512/224", P11Digest, + s("2.16.840.1.101.3.4.2.5", "OID.2.16.840.1.101.3.4.2.5"), + m(CKM_SHA512_224)); + d(MD, "SHA-512/256", P11Digest, + s("2.16.840.1.101.3.4.2.6", "OID.2.16.840.1.101.3.4.2.6"), + m(CKM_SHA512_256)); + + d(MAC, "HmacMD5", P11MAC, + m(CKM_MD5_HMAC)); + d(MAC, "HmacSHA1", P11MAC, + s("1.2.840.113549.2.7", "OID.1.2.840.113549.2.7"), + m(CKM_SHA_1_HMAC)); + d(MAC, "HmacSHA224", P11MAC, + s("1.2.840.113549.2.8", "OID.1.2.840.113549.2.8"), + m(CKM_SHA224_HMAC)); + d(MAC, "HmacSHA256", P11MAC, + s("1.2.840.113549.2.9", "OID.1.2.840.113549.2.9"), + m(CKM_SHA256_HMAC)); + d(MAC, "HmacSHA384", P11MAC, + s("1.2.840.113549.2.10", "OID.1.2.840.113549.2.10"), + m(CKM_SHA384_HMAC)); + d(MAC, "HmacSHA512", P11MAC, + s("1.2.840.113549.2.11", "OID.1.2.840.113549.2.11"), + m(CKM_SHA512_HMAC)); + d(MAC, "HmacSHA512/224", P11MAC, + s("1.2.840.113549.2.12", "OID.1.2.840.113549.2.12"), + m(CKM_SHA512_224_HMAC)); + d(MAC, "HmacSHA512/256", P11MAC, + s("1.2.840.113549.2.13", "OID.1.2.840.113549.2.13"), + m(CKM_SHA512_256_HMAC)); + + d(MAC, "SslMacMD5", P11MAC, + m(CKM_SSL3_MD5_MAC)); + d(MAC, "SslMacSHA1", P11MAC, + m(CKM_SSL3_SHA1_MAC)); + + d(KPG, "RSA", P11KeyPairGenerator, + s("1.2.840.113549.1.1", "OID.1.2.840.113549.1.1"), + m(CKM_RSA_PKCS_KEY_PAIR_GEN)); + + d(KPG, "DSA", P11KeyPairGenerator, + s("1.3.14.3.2.12", "1.2.840.10040.4.1", "OID.1.2.840.10040.4.1"), + m(CKM_DSA_KEY_PAIR_GEN)); + d(KPG, "DH", P11KeyPairGenerator, s("DiffieHellman"), + m(CKM_DH_PKCS_KEY_PAIR_GEN)); + d(KPG, "EC", P11KeyPairGenerator, + m(CKM_EC_KEY_PAIR_GEN)); + + d(KG, "ARCFOUR", P11KeyGenerator, s("RC4"), + m(CKM_RC4_KEY_GEN)); + d(KG, "DES", P11KeyGenerator, + m(CKM_DES_KEY_GEN)); + d(KG, "DESede", P11KeyGenerator, + m(CKM_DES3_KEY_GEN, CKM_DES2_KEY_GEN)); + d(KG, "AES", P11KeyGenerator, + m(CKM_AES_KEY_GEN)); + d(KG, "Blowfish", P11KeyGenerator, + m(CKM_BLOWFISH_KEY_GEN)); + + // register (Secret)KeyFactories if there are any mechanisms + // for a particular algorithm that we support + d(KF, "RSA", P11RSAKeyFactory, + s("1.2.840.113549.1.1", "OID.1.2.840.113549.1.1"), + m(CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(KF, "DSA", P11DSAKeyFactory, + s("1.3.14.3.2.12", "1.2.840.10040.4.1", "OID.1.2.840.10040.4.1"), + m(CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1)); + d(KF, "DH", P11DHKeyFactory, s("DiffieHellman"), + m(CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE)); + d(KF, "EC", P11DHKeyFactory, + m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, + CKM_ECDSA, CKM_ECDSA_SHA1)); + + // AlgorithmParameters for EC. + // Only needed until we have an EC implementation in the SUN provider. + d(AGP, "EC", "sun.security.util.ECParameters", + s("1.2.840.10045.2.1"), + m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, + CKM_ECDSA, CKM_ECDSA_SHA1)); + + d(AGP, "GCM", "sun.security.util.GCMParameters", + m(CKM_AES_GCM)); + + d(KA, "DH", P11KeyAgreement, s("DiffieHellman"), + m(CKM_DH_PKCS_DERIVE)); + d(KA, "ECDH", "sun.security.pkcs11.P11ECDHKeyAgreement", + m(CKM_ECDH1_DERIVE)); + + d(SKF, "ARCFOUR", P11SecretKeyFactory, s("RC4"), + m(CKM_RC4)); + d(SKF, "DES", P11SecretKeyFactory, + m(CKM_DES_CBC)); + d(SKF, "DESede", P11SecretKeyFactory, + m(CKM_DES3_CBC)); + d(SKF, "AES", P11SecretKeyFactory, + s("2.16.840.1.101.3.4.1", "OID.2.16.840.1.101.3.4.1"), + m(CKM_AES_CBC)); + d(SKF, "Blowfish", P11SecretKeyFactory, + m(CKM_BLOWFISH_CBC)); + + // XXX attributes for Ciphers (supported modes, padding) + d(CIP, "ARCFOUR", P11Cipher, s("RC4"), + m(CKM_RC4)); + d(CIP, "DES/CBC/NoPadding", P11Cipher, + m(CKM_DES_CBC)); + d(CIP, "DES/CBC/PKCS5Padding", P11Cipher, + m(CKM_DES_CBC_PAD, CKM_DES_CBC)); + d(CIP, "DES/ECB/NoPadding", P11Cipher, + m(CKM_DES_ECB)); + d(CIP, "DES/ECB/PKCS5Padding", P11Cipher, s("DES"), + m(CKM_DES_ECB)); + + d(CIP, "DESede/CBC/NoPadding", P11Cipher, + m(CKM_DES3_CBC)); + d(CIP, "DESede/CBC/PKCS5Padding", P11Cipher, + m(CKM_DES3_CBC_PAD, CKM_DES3_CBC)); + d(CIP, "DESede/ECB/NoPadding", P11Cipher, + m(CKM_DES3_ECB)); + d(CIP, "DESede/ECB/PKCS5Padding", P11Cipher, s("DESede"), + m(CKM_DES3_ECB)); + d(CIP, "AES/CBC/NoPadding", P11Cipher, + m(CKM_AES_CBC)); + d(CIP, "AES_128/CBC/NoPadding", P11Cipher, + s("2.16.840.1.101.3.4.1.2", "OID.2.16.840.1.101.3.4.1.2"), + m(CKM_AES_CBC)); + d(CIP, "AES_192/CBC/NoPadding", P11Cipher, + s("2.16.840.1.101.3.4.1.22", "OID.2.16.840.1.101.3.4.1.22"), + m(CKM_AES_CBC)); + d(CIP, "AES_256/CBC/NoPadding", P11Cipher, + s("2.16.840.1.101.3.4.1.42", "OID.2.16.840.1.101.3.4.1.42"), + m(CKM_AES_CBC)); + d(CIP, "AES/CBC/PKCS5Padding", P11Cipher, + m(CKM_AES_CBC_PAD, CKM_AES_CBC)); + d(CIP, "AES/ECB/NoPadding", P11Cipher, + m(CKM_AES_ECB)); + d(CIP, "AES_128/ECB/NoPadding", P11Cipher, + s("2.16.840.1.101.3.4.1.1", "OID.2.16.840.1.101.3.4.1.1"), + m(CKM_AES_ECB)); + d(CIP, "AES_192/ECB/NoPadding", P11Cipher, + s("2.16.840.1.101.3.4.1.21", "OID.2.16.840.1.101.3.4.1.21"), + m(CKM_AES_ECB)); + d(CIP, "AES_256/ECB/NoPadding", P11Cipher, + s("2.16.840.1.101.3.4.1.41", "OID.2.16.840.1.101.3.4.1.41"), + m(CKM_AES_ECB)); + d(CIP, "AES/ECB/PKCS5Padding", P11Cipher, s("AES"), + m(CKM_AES_ECB)); + d(CIP, "AES/CTR/NoPadding", P11Cipher, + m(CKM_AES_CTR)); + + d(CIP, "AES/GCM/NoPadding", P11AEADCipher, + m(CKM_AES_GCM)); + d(CIP, "AES_128/GCM/NoPadding", P11AEADCipher, + s("2.16.840.1.101.3.4.1.6", "OID.2.16.840.1.101.3.4.1.6"), + m(CKM_AES_GCM)); + d(CIP, "AES_192/GCM/NoPadding", P11AEADCipher, + s("2.16.840.1.101.3.4.1.26", "OID.2.16.840.1.101.3.4.1.26"), + m(CKM_AES_GCM)); + d(CIP, "AES_256/GCM/NoPadding", P11AEADCipher, + s("2.16.840.1.101.3.4.1.46", "OID.2.16.840.1.101.3.4.1.46"), + m(CKM_AES_GCM)); + + d(CIP, "Blowfish/CBC/NoPadding", P11Cipher, + m(CKM_BLOWFISH_CBC)); + d(CIP, "Blowfish/CBC/PKCS5Padding", P11Cipher, + m(CKM_BLOWFISH_CBC)); + + d(CIP, "RSA/ECB/PKCS1Padding", P11RSACipher, s("RSA"), + m(CKM_RSA_PKCS)); + d(CIP, "RSA/ECB/NoPadding", P11RSACipher, + m(CKM_RSA_X_509)); + + d(SIG, "RawDSA", P11Signature, s("NONEwithDSA"), + m(CKM_DSA)); + d(SIG, "DSA", P11Signature, + s("SHA1withDSA", "1.3.14.3.2.13", "1.3.14.3.2.27", + "1.2.840.10040.4.3", "OID.1.2.840.10040.4.3"), + m(CKM_DSA_SHA1, CKM_DSA)); + d(SIG, "SHA224withDSA", P11Signature, + s("2.16.840.1.101.3.4.3.1", "OID.2.16.840.1.101.3.4.3.1"), + m(CKM_DSA_SHA224)); + d(SIG, "SHA256withDSA", P11Signature, + s("2.16.840.1.101.3.4.3.2", "OID.2.16.840.1.101.3.4.3.2"), + m(CKM_DSA_SHA256)); + d(SIG, "SHA384withDSA", P11Signature, + s("2.16.840.1.101.3.4.3.3", "OID.2.16.840.1.101.3.4.3.3"), + m(CKM_DSA_SHA384)); + d(SIG, "SHA512withDSA", P11Signature, + s("2.16.840.1.101.3.4.3.4", "OID.2.16.840.1.101.3.4.3.4"), + m(CKM_DSA_SHA512)); + + d(SIG, "NONEwithECDSA", P11Signature, + m(CKM_ECDSA)); + d(SIG, "SHA1withECDSA", P11Signature, + s("ECDSA", "1.2.840.10045.4.1", "OID.1.2.840.10045.4.1"), + m(CKM_ECDSA_SHA1, CKM_ECDSA)); + d(SIG, "SHA224withECDSA", P11Signature, + s("1.2.840.10045.4.3.1", "OID.1.2.840.10045.4.3.1"), + m(CKM_ECDSA)); + d(SIG, "SHA256withECDSA", P11Signature, + s("1.2.840.10045.4.3.2", "OID.1.2.840.10045.4.3.2"), + m(CKM_ECDSA)); + d(SIG, "SHA384withECDSA", P11Signature, + s("1.2.840.10045.4.3.3", "OID.1.2.840.10045.4.3.3"), + m(CKM_ECDSA)); + d(SIG, "SHA512withECDSA", P11Signature, + s("1.2.840.10045.4.3.4", "OID.1.2.840.10045.4.3.4"), + m(CKM_ECDSA)); + d(SIG, "MD2withRSA", P11Signature, + s("1.2.840.113549.1.1.2", "OID.1.2.840.113549.1.1.2"), + m(CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "MD5withRSA", P11Signature, + s("1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4"), + m(CKM_MD5_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "SHA1withRSA", P11Signature, + s("1.2.840.113549.1.1.5", "OID.1.2.840.113549.1.1.5", + "1.3.14.3.2.29"), + m(CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "SHA224withRSA", P11Signature, + s("1.2.840.113549.1.1.14", "OID.1.2.840.113549.1.1.14"), + m(CKM_SHA224_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "SHA256withRSA", P11Signature, + s("1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11"), + m(CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "SHA384withRSA", P11Signature, + s("1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12"), + m(CKM_SHA384_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "SHA512withRSA", P11Signature, + s("1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13"), + m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); + d(SIG, "RSASSA-PSS", P11PSSSignature, + s("1.2.840.113549.1.1.10", "OID.1.2.840.113549.1.1.10"), + m(CKM_RSA_PKCS_PSS)); + d(SIG, "SHA1withRSASSA-PSS", P11PSSSignature, + m(CKM_SHA1_RSA_PKCS_PSS)); + d(SIG, "SHA224withRSASSA-PSS", P11PSSSignature, + m(CKM_SHA224_RSA_PKCS_PSS)); + d(SIG, "SHA256withRSASSA-PSS", P11PSSSignature, + m(CKM_SHA256_RSA_PKCS_PSS)); + d(SIG, "SHA384withRSASSA-PSS", P11PSSSignature, + m(CKM_SHA384_RSA_PKCS_PSS)); + d(SIG, "SHA512withRSASSA-PSS", P11PSSSignature, + m(CKM_SHA512_RSA_PKCS_PSS)); + + d(KG, "SunTlsRsaPremasterSecret", + "sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator", + s("SunTls12RsaPremasterSecret"), + m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN)); + d(KG, "SunTlsMasterSecret", + "sun.security.pkcs11.P11TlsMasterSecretGenerator", + m(CKM_SSL3_MASTER_KEY_DERIVE, CKM_TLS_MASTER_KEY_DERIVE, + CKM_SSL3_MASTER_KEY_DERIVE_DH, + CKM_TLS_MASTER_KEY_DERIVE_DH)); + d(KG, "SunTls12MasterSecret", + "sun.security.pkcs11.P11TlsMasterSecretGenerator", + m(CKM_TLS12_MASTER_KEY_DERIVE, CKM_TLS12_MASTER_KEY_DERIVE_DH)); + d(KG, "SunTlsKeyMaterial", + "sun.security.pkcs11.P11TlsKeyMaterialGenerator", + m(CKM_SSL3_KEY_AND_MAC_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE)); + d(KG, "SunTls12KeyMaterial", + "sun.security.pkcs11.P11TlsKeyMaterialGenerator", + m(CKM_TLS12_KEY_AND_MAC_DERIVE)); + d(KG, "SunTlsPrf", "sun.security.pkcs11.P11TlsPrfGenerator", + m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL)); + d(KG, "SunTls12Prf", "sun.security.pkcs11.P11TlsPrfGenerator", + m(CKM_TLS_MAC)); + } + + // background thread that periodically checks for token insertion + // if no token is present. We need to do that in a separate thread because + // the insertion check may block for quite a long time on some tokens. + private static class TokenPoller implements Runnable { + private final SunPKCS11 provider; + private volatile boolean enabled; + private TokenPoller(SunPKCS11 provider) { + this.provider = provider; + enabled = true; + } + public void run() { + int interval = provider.config.getInsertionCheckInterval(); + while (enabled) { + try { + Thread.sleep(interval); + } catch (InterruptedException e) { + break; + } + if (enabled == false) { + break; + } + try { + provider.initToken(null); + } catch (PKCS11Exception e) { + // ignore + } + } + } + void disable() { + enabled = false; + } + } + + // create the poller thread, if not already active + private void createPoller() { + if (poller != null) { + return; + } + TokenPoller poller = new TokenPoller(this); + Thread t = new Thread(poller, "Poller " + getName()); + t.setDaemon(true); + t.setPriority(Thread.MIN_PRIORITY); + t.start(); + this.poller = poller; + } + + // destroy the poller thread, if active + private void destroyPoller() { + if (poller != null) { + poller.disable(); + poller = null; + } + } + + private boolean hasValidToken() { + /* Commented out to work with Solaris softtoken impl which + returns 0-value flags, e.g. both REMOVABLE_DEVICE and + TOKEN_PRESENT are false, when it can't access the token. + if (removable == false) { + return true; + } + */ + Token token = this.token; + return (token != null) && token.isValid(); + } + + // destroy the token. Called if we detect that it has been removed + synchronized void uninitToken(Token token) { + if (this.token != token) { + // mismatch, our token must already be destroyed + return; + } + destroyPoller(); + this.token = null; + // unregister all algorithms + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + clear(); + return null; + } + }); + createPoller(); + } + + private static boolean isLegacy(CK_MECHANISM_INFO mechInfo) + throws PKCS11Exception { + // assume full support if no mech info available + // For vendor-specific mechanisms, often no mech info is provided + boolean partialSupport = false; + + if (mechInfo != null) { + if ((mechInfo.flags & CKF_DECRYPT) != 0) { + // non-legacy cipher mechs should support encryption + partialSupport |= ((mechInfo.flags & CKF_ENCRYPT) == 0); + } + if ((mechInfo.flags & CKF_VERIFY) != 0) { + // non-legacy signature mechs should support signing + partialSupport |= ((mechInfo.flags & CKF_SIGN) == 0); + } + } + return partialSupport; + } + + // test if a token is present and initialize this provider for it if so. + // does nothing if no token is found + // called from constructor and by poller + private void initToken(CK_SLOT_INFO slotInfo) throws PKCS11Exception { + if (slotInfo == null) { + slotInfo = p11.C_GetSlotInfo(slotID); + } + if (removable && (slotInfo.flags & CKF_TOKEN_PRESENT) == 0) { + createPoller(); + return; + } + destroyPoller(); + boolean showInfo = config.getShowInfo(); + if (showInfo) { + System.out.println("Slot info for slot " + slotID + ":"); + System.out.println(slotInfo); + } + final Token token = new Token(this); + if (showInfo) { + System.out.println + ("Token info for token in slot " + slotID + ":"); + System.out.println(token.tokenInfo); + } + long[] supportedMechanisms = p11.C_GetMechanismList(slotID); + + // Create a map from the various Descriptors to the "most + // preferred" mechanism that was defined during the + // static initialization. For example, DES/CBC/PKCS5Padding + // could be mapped to CKM_DES_CBC_PAD or CKM_DES_CBC. Prefer + // the earliest entry. When asked for "DES/CBC/PKCS5Padding", we + // return a CKM_DES_CBC_PAD. + final Map supportedAlgs = + new HashMap(); + + for (int i = 0; i < supportedMechanisms.length; i++) { + long longMech = supportedMechanisms[i]; + CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(longMech); + if (showInfo) { + System.out.println("Mechanism " + + Functions.getMechanismName(longMech) + ":"); + System.out.println(mechInfo == null? + (Constants.INDENT + "info n/a") : + mechInfo); + } + if (!config.isEnabled(longMech)) { + if (showInfo) { + System.out.println("DISABLED in configuration"); + } + continue; + } + if (isLegacy(mechInfo)) { + if (showInfo) { + System.out.println("DISABLED due to legacy"); + } + continue; + } + + // we do not know of mechs with the upper 32 bits set + if (longMech >>> 32 != 0) { + if (showInfo) { + System.out.println("DISABLED due to unknown mech value"); + } + continue; + } + int mech = (int)longMech; + Integer integerMech = Integer.valueOf(mech); + List ds = descriptors.get(integerMech); + if (ds == null) { + continue; + } + for (Descriptor d : ds) { + Integer oldMech = supportedAlgs.get(d); + if (oldMech == null) { + supportedAlgs.put(d, integerMech); + continue; + } + // See if there is something "more preferred" + // than what we currently have in the supportedAlgs + // map. + int intOldMech = oldMech.intValue(); + for (int j = 0; j < d.mechanisms.length; j++) { + int nextMech = d.mechanisms[j]; + if (mech == nextMech) { + supportedAlgs.put(d, integerMech); + break; + } else if (intOldMech == nextMech) { + break; + } + } + } + + } + + // register algorithms in provider + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + for (Map.Entry entry + : supportedAlgs.entrySet()) { + Descriptor d = entry.getKey(); + int mechanism = entry.getValue().intValue(); + Service s = d.service(token, mechanism); + putService(s); + } + if (((token.tokenInfo.flags & CKF_RNG) != 0) + && config.isEnabled(PCKM_SECURERANDOM) + && !token.sessionManager.lowMaxSessions()) { + // do not register SecureRandom if the token does + // not support many sessions. if we did, we might + // run out of sessions in the middle of a + // nextBytes() call where we cannot fail over. + putService(new P11Service(token, SR, "PKCS11", + "sun.security.pkcs11.P11SecureRandom", null, + PCKM_SECURERANDOM)); + } + if (config.isEnabled(PCKM_KEYSTORE)) { + putService(new P11Service(token, KS, "PKCS11", + "sun.security.pkcs11.P11KeyStore", + s("PKCS11-" + config.getName()), + PCKM_KEYSTORE)); + } + return null; + } + }); + + this.token = token; + } + + private static final class P11Service extends Service { + + private final Token token; + + private final long mechanism; + + P11Service(Token token, String type, String algorithm, + String className, String[] al, long mechanism) { + super(token.provider, type, algorithm, className, toList(al), null); + this.token = token; + this.mechanism = mechanism & 0xFFFFFFFFL; + } + + private static List toList(String[] aliases) { + return (aliases == null) ? null : Arrays.asList(aliases); + } + + public Object newInstance(Object param) + throws NoSuchAlgorithmException { + if (token.isValid() == false) { + throw new NoSuchAlgorithmException("Token has been removed"); + } + try { + return newInstance0(param); + } catch (PKCS11Exception e) { + throw new NoSuchAlgorithmException(e); + } + } + + public Object newInstance0(Object param) throws + PKCS11Exception, NoSuchAlgorithmException { + String algorithm = getAlgorithm(); + String type = getType(); + if (type == MD) { + return new P11Digest(token, algorithm, mechanism); + } else if (type == CIP) { + if (algorithm.startsWith("RSA")) { + return new P11RSACipher(token, algorithm, mechanism); + } else if (algorithm.endsWith("GCM/NoPadding")) { + return new P11AEADCipher(token, algorithm, mechanism); + } else { + return new P11Cipher(token, algorithm, mechanism); + } + } else if (type == SIG) { + if (algorithm.indexOf("RSASSA-PSS") != -1) { + return new P11PSSSignature(token, algorithm, mechanism); + } else { + return new P11Signature(token, algorithm, mechanism); + } + } else if (type == MAC) { + return new P11Mac(token, algorithm, mechanism); + } else if (type == KPG) { + return new P11KeyPairGenerator(token, algorithm, mechanism); + } else if (type == KA) { + if (algorithm.equals("ECDH")) { + return new P11ECDHKeyAgreement(token, algorithm, mechanism); + } else { + return new P11KeyAgreement(token, algorithm, mechanism); + } + } else if (type == KF) { + return token.getKeyFactory(algorithm); + } else if (type == SKF) { + return new P11SecretKeyFactory(token, algorithm); + } else if (type == KG) { + // reference equality + if (algorithm == "SunTlsRsaPremasterSecret") { + return new P11TlsRsaPremasterSecretGenerator( + token, algorithm, mechanism); + } else if (algorithm == "SunTlsMasterSecret" + || algorithm == "SunTls12MasterSecret") { + return new P11TlsMasterSecretGenerator( + token, algorithm, mechanism); + } else if (algorithm == "SunTlsKeyMaterial" + || algorithm == "SunTls12KeyMaterial") { + return new P11TlsKeyMaterialGenerator( + token, algorithm, mechanism); + } else if (algorithm == "SunTlsPrf" + || algorithm == "SunTls12Prf") { + return new P11TlsPrfGenerator(token, algorithm, mechanism); + } else { + return new P11KeyGenerator(token, algorithm, mechanism); + } + } else if (type == SR) { + return token.getRandom(); + } else if (type == KS) { + return token.getKeyStore(); + } else if (type == AGP) { + if (algorithm == "EC") { + return new com.sunyard.security.util.ECParameters(); + } else if (algorithm == "GCM") { + return new com.sunyard.security.util.GCMParameters(); + } else { + throw new NoSuchAlgorithmException("Unsupported algorithm: " + + algorithm); + } + } else { + throw new NoSuchAlgorithmException("Unknown type: " + type); + } + } + + public boolean supportsParameter(Object param) { + if ((param == null) || (token.isValid() == false)) { + return false; + } + if (param instanceof Key == false) { + throw new InvalidParameterException("Parameter must be a Key"); + } + String algorithm = getAlgorithm(); + String type = getType(); + Key key = (Key)param; + String keyAlgorithm = key.getAlgorithm(); + // RSA signatures and cipher + if (((type == CIP) && algorithm.startsWith("RSA")) + || (type == SIG) && (algorithm.indexOf("RSA") != -1)) { + if (keyAlgorithm.equals("RSA") == false) { + return false; + } + return isLocalKey(key) + || (key instanceof RSAPrivateKey) + || (key instanceof RSAPublicKey); + } + // EC + if (((type == KA) && algorithm.equals("ECDH")) + || ((type == SIG) && algorithm.endsWith("ECDSA"))) { + if (keyAlgorithm.equals("EC") == false) { + return false; + } + return isLocalKey(key) + || (key instanceof ECPrivateKey) + || (key instanceof ECPublicKey); + } + // DSA signatures + if ((type == SIG) && algorithm.endsWith("DSA")) { + if (keyAlgorithm.equals("DSA") == false) { + return false; + } + return isLocalKey(key) + || (key instanceof DSAPrivateKey) + || (key instanceof DSAPublicKey); + } + // MACs and symmetric ciphers + if ((type == CIP) || (type == MAC)) { + // do not check algorithm name, mismatch is unlikely anyway + return isLocalKey(key) || "RAW".equals(key.getFormat()); + } + // DH key agreement + if (type == KA) { + if (keyAlgorithm.equals("DH") == false) { + return false; + } + return isLocalKey(key) + || (key instanceof DHPrivateKey) + || (key instanceof DHPublicKey); + } + // should not reach here, + // unknown engine type or algorithm + throw new AssertionError + ("SunPKCS11 error: " + type + ", " + algorithm); + } + + private boolean isLocalKey(Key key) { + return (key instanceof P11Key) && (((P11Key)key).token == token); + } + + public String toString() { + return super.toString() + + " (" + Functions.getMechanismName(mechanism) + ")"; + } + + } + + /** + * Log in to this provider. + * + *

If the token expects a PIN to be supplied by the caller, + * the handler implementation must support + * a PasswordCallback. + * + *

To determine if the token supports a protected authentication path, + * the CK_TOKEN_INFO flag, CKF_PROTECTED_AUTHENTICATION_PATH, is consulted. + * + * @param subject this parameter is ignored + * @param handler the CallbackHandler used by + * this provider to communicate with the caller + * + * @exception LoginException if the login operation fails + * @exception SecurityException if the does not pass a security check for + * SecurityPermission("authProvider.name"), + * where name is the value returned by + * this provider's getName method + */ + public void login(Subject subject, CallbackHandler handler) + throws LoginException { + + // security check + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (debug != null) { + debug.println("checking login permission"); + } + sm.checkPermission(new SecurityPermission + ("authProvider." + this.getName())); + } + + if (hasValidToken() == false) { + throw new LoginException("No token present"); + } + + // see if a login is required + + if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) { + if (debug != null) { + debug.println("login operation not required for token - " + + "ignoring login request"); + } + return; + } + + // see if user already logged in + + try { + if (token.isLoggedInNow(null)) { + // user already logged in + if (debug != null) { + debug.println("user already logged in"); + } + return; + } + } catch (PKCS11Exception e) { + // ignore - fall thru and attempt login + } + + // get the pin if necessary + + char[] pin = null; + if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) { + + // get password + + CallbackHandler myHandler = getCallbackHandler(handler); + if (myHandler == null) { + // XXX PolicyTool is dependent on this message text + throw new LoginException + ("no password provided, and no callback handler " + + "available for retrieving password"); + } + + java.text.MessageFormat form = new java.text.MessageFormat + (ResourcesMgr.getString + ("PKCS11.Token.providerName.Password.")); + Object[] source = { getName() }; + + PasswordCallback pcall = new PasswordCallback(form.format(source), + false); + Callback[] callbacks = { pcall }; + try { + myHandler.handle(callbacks); + } catch (Exception e) { + LoginException le = new LoginException + ("Unable to perform password callback"); + le.initCause(e); + throw le; + } + + pin = pcall.getPassword(); + pcall.clearPassword(); + if (pin == null) { + if (debug != null) { + debug.println("caller passed NULL pin"); + } + } + } + + // perform token login + + Session session = null; + try { + session = token.getOpSession(); + + // pin is NULL if using CKF_PROTECTED_AUTHENTICATION_PATH + p11.C_Login(session.id(), CKU_USER, pin); + if (debug != null) { + debug.println("login succeeded"); + } + } catch (PKCS11Exception pe) { + if (pe.getErrorCode() == CKR_USER_ALREADY_LOGGED_IN) { + // let this one go + if (debug != null) { + debug.println("user already logged in"); + } + return; + } else if (pe.getErrorCode() == CKR_PIN_INCORRECT) { + FailedLoginException fle = new FailedLoginException(); + fle.initCause(pe); + throw fle; + } else { + LoginException le = new LoginException(); + le.initCause(pe); + throw le; + } + } finally { + token.releaseSession(session); + if (pin != null) { + Arrays.fill(pin, ' '); + } + } + + // we do not store the PIN in the subject for now + } + + /** + * Log out from this provider + * + * @exception LoginException if the logout operation fails + * @exception SecurityException if the does not pass a security check for + * SecurityPermission("authProvider.name"), + * where name is the value returned by + * this provider's getName method + */ + public void logout() throws LoginException { + + // security check + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission + (new SecurityPermission("authProvider." + this.getName())); + } + + if (hasValidToken() == false) { + // app may call logout for cleanup, allow + return; + } + + if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) { + if (debug != null) { + debug.println("logout operation not required for token - " + + "ignoring logout request"); + } + return; + } + + try { + if (token.isLoggedInNow(null) == false) { + if (debug != null) { + debug.println("user not logged in"); + } + return; + } + } catch (PKCS11Exception e) { + // ignore + } + + // perform token logout + + Session session = null; + try { + session = token.getOpSession(); + p11.C_Logout(session.id()); + if (debug != null) { + debug.println("logout succeeded"); + } + } catch (PKCS11Exception pe) { + if (pe.getErrorCode() == CKR_USER_NOT_LOGGED_IN) { + // let this one go + if (debug != null) { + debug.println("user not logged in"); + } + return; + } + LoginException le = new LoginException(); + le.initCause(pe); + throw le; + } finally { + token.releaseSession(session); + } + } + + /** + * Set a CallbackHandler + * + *

The provider uses this handler if one is not passed to the + * login method. The provider also uses this handler + * if it invokes login on behalf of callers. + * In either case if a handler is not set via this method, + * the provider queries the + * auth.login.defaultCallbackHandler security property + * for the fully qualified class name of a default handler implementation. + * If the security property is not set, + * the provider is assumed to have alternative means + * for obtaining authentication information. + * + * @param handler a CallbackHandler for obtaining + * authentication information, which may be null + * + * @exception SecurityException if the caller does not pass a + * security check for + * SecurityPermission("authProvider.name"), + * where name is the value returned by + * this provider's getName method + */ + public void setCallbackHandler(CallbackHandler handler) { + + // security check + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission + (new SecurityPermission("authProvider." + this.getName())); + } + + synchronized (LOCK_HANDLER) { + pHandler = handler; + } + } + + private CallbackHandler getCallbackHandler(CallbackHandler handler) { + + // get default handler if necessary + + if (handler != null) { + return handler; + } + + if (debug != null) { + debug.println("getting provider callback handler"); + } + + synchronized (LOCK_HANDLER) { + // see if handler was set via setCallbackHandler + if (pHandler != null) { + return pHandler; + } + + try { + if (debug != null) { + debug.println("getting default callback handler"); + } + + CallbackHandler myHandler = AccessController.doPrivileged + (new PrivilegedExceptionAction() { + public CallbackHandler run() throws Exception { + + String defaultHandler = + java.security.Security.getProperty + ("auth.login.defaultCallbackHandler"); + + if (defaultHandler == null || + defaultHandler.length() == 0) { + + // ok + if (debug != null) { + debug.println("no default handler set"); + } + return null; + } + + Class c = Class.forName + (defaultHandler, + true, + Thread.currentThread().getContextClassLoader()); + return (CallbackHandler)c.newInstance(); + } + }); + + // save it + pHandler = myHandler; + return myHandler; + + } catch (PrivilegedActionException pae) { + // ok + if (debug != null) { + debug.println("Unable to load default callback handler"); + pae.printStackTrace(); + } + } + } + return null; + } + + private Object writeReplace() throws ObjectStreamException { + return new SunPKCS11Rep(this); + } + + /** + * Serialized representation of the SunPKCS11 provider. + */ + private static class SunPKCS11Rep implements Serializable { + + static final long serialVersionUID = -2896606995897745419L; + + private final String providerName; + + private final String configName; + + SunPKCS11Rep(SunPKCS11 provider) throws NotSerializableException { + providerName = provider.getName(); + configName = provider.configName; + if (Security.getProvider(providerName) != provider) { + throw new NotSerializableException("Only SunPKCS11 providers " + + "installed in java.security.Security can be serialized"); + } + } + + private Object readResolve() throws ObjectStreamException { + SunPKCS11 p = (SunPKCS11)Security.getProvider(providerName); + if ((p == null) || (p.configName.equals(configName) == false)) { + throw new NotSerializableException("Could not find " + + providerName + " in installed providers"); + } + return p; + } + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/TemplateManager.java b/src/main/java/com/sunyard/security/pkcs11/TemplateManager.java new file mode 100644 index 0000000..4942259 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/TemplateManager.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; +import java.util.concurrent.*; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * TemplateManager class. + * + * Not all PKCS#11 tokens are created equal. One token may require that one + * value is specified when creating a certain type of object. Another token + * may require a different value. Yet another token may only work if the + * attribute is not specified at all. + * + * In order to allow an application to work unmodified with all those + * different tokens, the SunPKCS11 provider makes the attributes that are + * specified and their value configurable. Hence, only the SunPKCS11 + * configuration file has to be tweaked at deployment time to allow all + * existing applications to be used. + * + * The template manager is responsible for reading the attribute configuration + * information and to make it available to the various internal components + * of the SunPKCS11 provider. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +final class TemplateManager { + + private final static boolean DEBUG = false; + + // constant for any operation (either O_IMPORT or O_GENERATE) + final static String O_ANY = "*"; + // constant for operation create ("importing" existing key material) + final static String O_IMPORT = "import"; + // constant for operation generate (generating new key material) + final static String O_GENERATE = "generate"; + + private static class KeyAndTemplate { + final TemplateKey key; + final Template template; + + KeyAndTemplate(TemplateKey key, Template template) { + this.key = key; + this.template = template; + } + } + + // primitive templates contains the individual template configuration + // entries from the configuration file + private final List primitiveTemplates; + + // composite templates is a cache of the exact configuration template for + // each specific TemplateKey (no wildcards). the entries are created + // on demand during first use by compositing all applicable + // primitive template entries. the result is then stored in this map + // for performance + private final Map compositeTemplates; + + TemplateManager() { + primitiveTemplates = new ArrayList(); + compositeTemplates = new ConcurrentHashMap(); + } + + // add a template. Called by Config. + void addTemplate(String op, long objectClass, long keyAlgorithm, + CK_ATTRIBUTE[] attrs) { + TemplateKey key = new TemplateKey(op, objectClass, keyAlgorithm); + Template template = new Template(attrs); + if (DEBUG) { + System.out.println("Adding " + key + " -> " + template); + } + primitiveTemplates.add(new KeyAndTemplate(key, template)); + } + + private Template getTemplate(TemplateKey key) { + Template template = compositeTemplates.get(key); + if (template == null) { + template = buildCompositeTemplate(key); + compositeTemplates.put(key, template); + } + return template; + } + + // Get the attributes for the requested op and combine them with attrs. + // This is the method called by the implementation to obtain the + // attributes. + CK_ATTRIBUTE[] getAttributes(String op, long type, long alg, + CK_ATTRIBUTE[] attrs) { + TemplateKey key = new TemplateKey(op, type, alg); + Template template = getTemplate(key); + CK_ATTRIBUTE[] newAttrs = template.getAttributes(attrs); + if (DEBUG) { + System.out.println(key + " -> " + Arrays.asList(newAttrs)); + } + return newAttrs; + } + + // build a composite template for the given key + private Template buildCompositeTemplate(TemplateKey key) { + Template comp = new Template(); + // iterate through primitive templates and add all that apply + for (KeyAndTemplate entry : primitiveTemplates) { + if (entry.key.appliesTo(key)) { + comp.add(entry.template); + } + } + return comp; + } + + /** + * Nested class representing a template identifier. + */ + private static final class TemplateKey { + final String operation; + final long keyType; + final long keyAlgorithm; + TemplateKey(String operation, long keyType, long keyAlgorithm) { + this.operation = operation; + this.keyType = keyType; + this.keyAlgorithm = keyAlgorithm; + } + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TemplateKey == false) { + return false; + } + TemplateKey other = (TemplateKey)obj; + boolean match = this.operation.equals(other.operation) + && (this.keyType == other.keyType) + && (this.keyAlgorithm == other.keyAlgorithm); + return match; + } + public int hashCode() { + return operation.hashCode() + (int)keyType + (int)keyAlgorithm; + } + boolean appliesTo(TemplateKey key) { + if (operation.equals(O_ANY) || operation.equals(key.operation)) { + if ((keyType == PCKO_ANY) || (keyType == key.keyType)) { + if ((keyAlgorithm == PCKK_ANY) + || (keyAlgorithm == key.keyAlgorithm)) { + return true; + } + } + } + return false; + } + public String toString() { + return "(" + operation + "," + + Functions.getObjectClassName(keyType) + + "," + Functions.getKeyName(keyAlgorithm) + ")"; + } + } + + /** + * Nested class representing template attributes. + */ + private static final class Template { + + private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0]; + + private CK_ATTRIBUTE[] attributes; + + Template() { + attributes = A0; + } + + Template(CK_ATTRIBUTE[] attributes) { + this.attributes = attributes; + } + + void add(Template template) { + attributes = getAttributes(template.attributes); + } + + CK_ATTRIBUTE[] getAttributes(CK_ATTRIBUTE[] attrs) { + return combine(attributes, attrs); + } + + /** + * Combine two sets of attributes. The second set has precedence + * over the first and overrides its settings. + */ + private static CK_ATTRIBUTE[] combine(CK_ATTRIBUTE[] attrs1, + CK_ATTRIBUTE[] attrs2) { + List attrs = new ArrayList(); + for (CK_ATTRIBUTE attr : attrs1) { + if (attr.pValue != null) { + attrs.add(attr); + } + } + for (CK_ATTRIBUTE attr2 : attrs2) { + long type = attr2.type; + for (CK_ATTRIBUTE attr1 : attrs1) { + if (attr1.type == type) { + attrs.remove(attr1); + } + } + if (attr2.pValue != null) { + attrs.add(attr2); + } + } + return attrs.toArray(A0); + } + + public String toString() { + return Arrays.asList(attributes).toString(); + } + + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/Token.java b/src/main/java/com/sunyard/security/pkcs11/Token.java new file mode 100644 index 0000000..d123155 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/Token.java @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.io.*; +import java.lang.ref.*; + +import java.security.*; +import javax.security.auth.login.LoginException; + +import sun.security.jca.JCAUtil; + +import com.sunyard.security.pkcs11.wrapper.*; +import static com.sunyard.security.pkcs11.TemplateManager.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * PKCS#11 token. + * + * @author Andreas Sterbenz + * @since 1.5 + */ +class Token implements Serializable { + + // need to be serializable to allow SecureRandom to be serialized + private static final long serialVersionUID = 2541527649100571747L; + + // how often to check if the token is still present (in ms) + // this is different from checking if a token has been inserted, + // that is done in SunPKCS11. Currently 50 ms. + private final static long CHECK_INTERVAL = 50; + + final SunPKCS11 provider; + + final PKCS11 p11; + + final Config config; + + final CK_TOKEN_INFO tokenInfo; + + // session manager to pool sessions + final SessionManager sessionManager; + + // template manager to customize the attributes used when creating objects + private final TemplateManager templateManager; + + // flag indicating whether we need to explicitly cancel operations + // we started on the token. If false, we assume operations are + // automatically cancelled once we start another one + final boolean explicitCancel; + + // translation cache for secret keys + final KeyCache secretCache; + + // translation cache for asymmetric keys (public and private) + final KeyCache privateCache; + + // cached instances of the various key factories, initialized on demand + private volatile P11KeyFactory rsaFactory, dsaFactory, dhFactory, ecFactory; + + // table which maps mechanisms to the corresponding cached + // MechanismInfo objects + private final Map mechInfoMap; + + // single SecureRandomSpi instance we use per token + // initialized on demand (if supported) + private volatile P11SecureRandom secureRandom; + + // single KeyStoreSpi instance we use per provider + // initialized on demand + private volatile P11KeyStore keyStore; + + // whether this token is a removable token + private final boolean removable; + + // for removable tokens: whether this token is valid or has been removed + private volatile boolean valid; + + // for removable tokens: time last checked for token presence + private long lastPresentCheck; + + // unique token id, used for serialization only + private byte[] tokenId; + + // flag indicating whether the token is write protected + private boolean writeProtected; + + // flag indicating whether we are logged in + private volatile boolean loggedIn; + + // time we last checked login status + private long lastLoginCheck; + + // mutex for token-present-check + private final static Object CHECK_LOCK = new Object(); + + // object for indicating unsupported mechanism in 'mechInfoMap' + private final static CK_MECHANISM_INFO INVALID_MECH = + new CK_MECHANISM_INFO(0, 0, 0); + + // flag indicating whether the token supports raw secret key material import + private Boolean supportsRawSecretKeyImport; + + Token(SunPKCS11 provider) throws PKCS11Exception { + this.provider = provider; + this.removable = provider.removable; + this.valid = true; + p11 = provider.p11; + config = provider.config; + tokenInfo = p11.C_GetTokenInfo(provider.slotID); + writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0; + // create session manager and open a test session + SessionManager sessionManager; + try { + sessionManager = new SessionManager(this); + Session s = sessionManager.getOpSession(); + sessionManager.releaseSession(s); + } catch (PKCS11Exception e) { + if (writeProtected) { + throw e; + } + // token might not permit RW sessions even though + // CKF_WRITE_PROTECTED is not set + writeProtected = true; + sessionManager = new SessionManager(this); + Session s = sessionManager.getOpSession(); + sessionManager.releaseSession(s); + } + this.sessionManager = sessionManager; + secretCache = new KeyCache(); + privateCache = new KeyCache(); + templateManager = config.getTemplateManager(); + explicitCancel = config.getExplicitCancel(); + mechInfoMap = + new ConcurrentHashMap(10); + } + + boolean isWriteProtected() { + return writeProtected; + } + + // return whether the token supports raw secret key material import + boolean supportsRawSecretKeyImport() { + if (supportsRawSecretKeyImport == null) { + SecureRandom random = JCAUtil.getSecureRandom(); + byte[] encoded = new byte[48]; + random.nextBytes(encoded); + + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3]; + attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); + attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET); + attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded); + + Session session = null; + try { + attributes = getAttributes(O_IMPORT, + CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); + session = getObjSession(); + long keyID = p11.C_CreateObject(session.id(), attributes); + + supportsRawSecretKeyImport = Boolean.TRUE; + } catch (PKCS11Exception e) { + supportsRawSecretKeyImport = Boolean.FALSE; + } finally { + releaseSession(session); + } + } + + return supportsRawSecretKeyImport; + } + + // return whether we are logged in + // uses cached result if current. session is optional and may be null + boolean isLoggedIn(Session session) throws PKCS11Exception { + // volatile load first + boolean loggedIn = this.loggedIn; + long time = System.currentTimeMillis(); + if (time - lastLoginCheck > CHECK_INTERVAL) { + loggedIn = isLoggedInNow(session); + lastLoginCheck = time; + } + return loggedIn; + } + + // return whether we are logged in now + // does not use cache + boolean isLoggedInNow(Session session) throws PKCS11Exception { + boolean allocSession = (session == null); + try { + if (allocSession) { + session = getOpSession(); + } + CK_SESSION_INFO info = p11.C_GetSessionInfo(session.id()); + boolean loggedIn = (info.state == CKS_RO_USER_FUNCTIONS) || + (info.state == CKS_RW_USER_FUNCTIONS); + this.loggedIn = loggedIn; + return loggedIn; + } finally { + if (allocSession) { + releaseSession(session); + } + } + } + + // ensure that we are logged in + // call provider.login() if not + void ensureLoggedIn(Session session) throws PKCS11Exception, LoginException { + if (isLoggedIn(session) == false) { + provider.login(null, null); + } + } + + // return whether this token object is valid (i.e. token not removed) + // returns value from last check, does not perform new check + boolean isValid() { + if (removable == false) { + return true; + } + return valid; + } + + void ensureValid() { + if (isValid() == false) { + throw new ProviderException("Token has been removed"); + } + } + + // return whether a token is present (i.e. token not removed) + // returns cached value if current, otherwise performs new check + boolean isPresent(long sessionID) { + if (removable == false) { + return true; + } + if (valid == false) { + return false; + } + long time = System.currentTimeMillis(); + if ((time - lastPresentCheck) >= CHECK_INTERVAL) { + synchronized (CHECK_LOCK) { + if ((time - lastPresentCheck) >= CHECK_INTERVAL) { + boolean ok = false; + try { + // check if token still present + CK_SLOT_INFO slotInfo = + provider.p11.C_GetSlotInfo(provider.slotID); + if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) { + // if the token has been removed and re-inserted, + // the token should return an error + CK_SESSION_INFO sessInfo = + provider.p11.C_GetSessionInfo + (sessionID); + ok = true; + } + } catch (PKCS11Exception e) { + // empty + } + valid = ok; + lastPresentCheck = System.currentTimeMillis(); + if (ok == false) { + destroy(); + } + } + } + } + return valid; + } + + void destroy() { + valid = false; + provider.uninitToken(this); + } + + Session getObjSession() throws PKCS11Exception { + return sessionManager.getObjSession(); + } + + Session getOpSession() throws PKCS11Exception { + return sessionManager.getOpSession(); + } + + Session releaseSession(Session session) { + return sessionManager.releaseSession(session); + } + + Session killSession(Session session) { + return sessionManager.killSession(session); + } + + CK_ATTRIBUTE[] getAttributes(String op, long type, long alg, + CK_ATTRIBUTE[] attrs) throws PKCS11Exception { + CK_ATTRIBUTE[] newAttrs = + templateManager.getAttributes(op, type, alg, attrs); + for (CK_ATTRIBUTE attr : newAttrs) { + if (attr.type == CKA_TOKEN) { + if (attr.getBoolean()) { + try { + ensureLoggedIn(null); + } catch (LoginException e) { + throw new ProviderException("Login failed", e); + } + } + // break once we have found a CKA_TOKEN attribute + break; + } + } + return newAttrs; + } + + P11KeyFactory getKeyFactory(String algorithm) { + P11KeyFactory f; + if (algorithm.equals("RSA")) { + f = rsaFactory; + if (f == null) { + f = new P11RSAKeyFactory(this, algorithm); + rsaFactory = f; + } + } else if (algorithm.equals("DSA")) { + f = dsaFactory; + if (f == null) { + f = new P11DSAKeyFactory(this, algorithm); + dsaFactory = f; + } + } else if (algorithm.equals("DH")) { + f = dhFactory; + if (f == null) { + f = new P11DHKeyFactory(this, algorithm); + dhFactory = f; + } + } else if (algorithm.equals("EC")) { + f = ecFactory; + if (f == null) { + f = new P11ECKeyFactory(this, algorithm); + ecFactory = f; + } + } else { + throw new ProviderException("Unknown algorithm " + algorithm); + } + return f; + } + + P11SecureRandom getRandom() { + if (secureRandom == null) { + secureRandom = new P11SecureRandom(this); + } + return secureRandom; + } + + P11KeyStore getKeyStore() { + if (keyStore == null) { + keyStore = new P11KeyStore(this); + } + return keyStore; + } + + CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception { + CK_MECHANISM_INFO result = mechInfoMap.get(mechanism); + if (result == null) { + try { + result = p11.C_GetMechanismInfo(provider.slotID, + mechanism); + mechInfoMap.put(mechanism, result); + } catch (PKCS11Exception e) { + if (e.getErrorCode() != PKCS11Constants.CKR_MECHANISM_INVALID) { + throw e; + } else { + mechInfoMap.put(mechanism, INVALID_MECH); + } + } + } else if (result == INVALID_MECH) { + result = null; + } + return result; + } + + private synchronized byte[] getTokenId() { + if (tokenId == null) { + SecureRandom random = JCAUtil.getSecureRandom(); + tokenId = new byte[20]; + random.nextBytes(tokenId); + serializedTokens.add(new WeakReference(this)); + } + return tokenId; + } + + // list of all tokens that have been serialized within this VM + // NOTE that elements are never removed from this list + // the assumption is that the number of tokens that are serialized + // is relatively small + private static final List> serializedTokens = + new ArrayList>(); + + private Object writeReplace() throws ObjectStreamException { + if (isValid() == false) { + throw new InvalidObjectException("Token has been removed"); + } + return new TokenRep(this); + } + + /** + * Restores the state of this object from the stream. + *

+ * Deserialization of this object is not supported. + * + * @param stream the {@code ObjectInputStream} from which data is read + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a serialized class cannot be loaded + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + throw new InvalidObjectException( + "Tokens are not directly deserializable"); + } + + // serialized representation of a token + // tokens can only be de-serialized within the same VM invocation + // and if the token has not been removed in the meantime + private static class TokenRep implements Serializable { + + private static final long serialVersionUID = 3503721168218219807L; + + private final byte[] tokenId; + + TokenRep(Token token) { + tokenId = token.getTokenId(); + } + + private Object readResolve() throws ObjectStreamException { + for (Reference tokenRef : serializedTokens) { + Token token = tokenRef.get(); + if ((token != null) && token.isValid()) { + if (Arrays.equals(token.getTokenId(), tokenId)) { + return token; + } + } + } + throw new InvalidObjectException("Could not find token"); + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java new file mode 100644 index 0000000..2df48d0 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * This class represents the necessary parameters required by + * the CKM_AES_CTR mechanism as defined in CK_AES_CTR_PARAMS structure.

+ * PKCS#11 structure: + *

+ * typedef struct CK_AES_CTR_PARAMS {
+ *   CK_ULONG ulCounterBits;
+ *   CK_BYTE cb[16];
+ * } CK_AES_CTR_PARAMS;
+ * 
+ * + * @author Yu-Ching Valerie Peng + * @since 1.7 + */ +public class CK_AES_CTR_PARAMS { + + private final long ulCounterBits; + private final byte cb[]; + + public CK_AES_CTR_PARAMS(byte[] cb) { + ulCounterBits = 128; + this.cb = cb.clone(); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("ulCounterBits: "); + buffer.append(ulCounterBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("cb: "); + buffer.append(Functions.toHexString(cb)); + + return buffer.toString(); + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ATTRIBUTE.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ATTRIBUTE.java new file mode 100644 index 0000000..73ecf3e --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ATTRIBUTE.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.math.BigInteger; + +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * class CK_ATTRIBUTE includes the type, value and length of an attribute.

+ * PKCS#11 structure: + *

+ * typedef struct CK_ATTRIBUTE {  
+ *   CK_ATTRIBUTE_TYPE type;  
+ *   CK_VOID_PTR pValue;  
+ *   CK_ULONG ulValueLen;
+ * } CK_ATTRIBUTE;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_ATTRIBUTE { + + // common attributes + // NOTE that CK_ATTRIBUTE is a mutable classes but these attributes + // *MUST NEVER* be modified, e.g. by using them in a + // C_GetAttributeValue() call! + + public final static CK_ATTRIBUTE TOKEN_FALSE = + new CK_ATTRIBUTE(CKA_TOKEN, false); + + public final static CK_ATTRIBUTE SENSITIVE_FALSE = + new CK_ATTRIBUTE(CKA_SENSITIVE, false); + + public final static CK_ATTRIBUTE EXTRACTABLE_TRUE = + new CK_ATTRIBUTE(CKA_EXTRACTABLE, true); + + public final static CK_ATTRIBUTE ENCRYPT_TRUE = + new CK_ATTRIBUTE(CKA_ENCRYPT, true); + + public final static CK_ATTRIBUTE DECRYPT_TRUE = + new CK_ATTRIBUTE(CKA_DECRYPT, true); + + public final static CK_ATTRIBUTE WRAP_TRUE = + new CK_ATTRIBUTE(CKA_WRAP, true); + + public final static CK_ATTRIBUTE UNWRAP_TRUE = + new CK_ATTRIBUTE(CKA_UNWRAP, true); + + public final static CK_ATTRIBUTE SIGN_TRUE = + new CK_ATTRIBUTE(CKA_SIGN, true); + + public final static CK_ATTRIBUTE VERIFY_TRUE = + new CK_ATTRIBUTE(CKA_VERIFY, true); + + public final static CK_ATTRIBUTE SIGN_RECOVER_TRUE = + new CK_ATTRIBUTE(CKA_SIGN_RECOVER, true); + + public final static CK_ATTRIBUTE VERIFY_RECOVER_TRUE = + new CK_ATTRIBUTE(CKA_VERIFY_RECOVER, true); + + public final static CK_ATTRIBUTE DERIVE_TRUE = + new CK_ATTRIBUTE(CKA_DERIVE, true); + + public final static CK_ATTRIBUTE ENCRYPT_NULL = + new CK_ATTRIBUTE(CKA_ENCRYPT); + + public final static CK_ATTRIBUTE DECRYPT_NULL = + new CK_ATTRIBUTE(CKA_DECRYPT); + + public final static CK_ATTRIBUTE WRAP_NULL = + new CK_ATTRIBUTE(CKA_WRAP); + + public final static CK_ATTRIBUTE UNWRAP_NULL = + new CK_ATTRIBUTE(CKA_UNWRAP); + + public CK_ATTRIBUTE() { + // empty + } + + public CK_ATTRIBUTE(long type) { + this.type = type; + } + + public CK_ATTRIBUTE(long type, Object pValue) { + this.type = type; + this.pValue = pValue; + } + + public CK_ATTRIBUTE(long type, boolean value) { + this.type = type; + this.pValue = Boolean.valueOf(value); + } + + public CK_ATTRIBUTE(long type, long value) { + this.type = type; + this.pValue = Long.valueOf(value); + } + + public CK_ATTRIBUTE(long type, BigInteger value) { + this.type = type; + this.pValue = sun.security.pkcs11.P11Util.getMagnitude(value); + } + + public BigInteger getBigInteger() { + if (pValue instanceof byte[] == false) { + throw new RuntimeException("Not a byte[]"); + } + return new BigInteger(1, (byte[])pValue); + } + + public boolean getBoolean() { + if (pValue instanceof Boolean == false) { + throw new RuntimeException + ("Not a Boolean: " + pValue.getClass().getName()); + } + return ((Boolean)pValue).booleanValue(); + } + + public char[] getCharArray() { + if (pValue instanceof char[] == false) { + throw new RuntimeException("Not a char[]"); + } + return (char[])pValue; + } + + public byte[] getByteArray() { + if (pValue instanceof byte[] == false) { + throw new RuntimeException("Not a byte[]"); + } + return (byte[])pValue; + } + + public long getLong() { + if (pValue instanceof Long == false) { + throw new RuntimeException + ("Not a Long: " + pValue.getClass().getName()); + } + return ((Long)pValue).longValue(); + } + + /** + * PKCS#11: + *
+     *   CK_ATTRIBUTE_TYPE type;
+     * 
+ */ + public long type; + + /** + * PKCS#11: + *
+     *   CK_VOID_PTR pValue;
+     *   CK_ULONG ulValueLen;
+     * 
+ */ + public Object pValue; + + /** + * Returns the string representation of CK_ATTRIBUTE. + * + * @return the string representation of CK_ATTRIBUTE + */ + public String toString() { + String prefix = Functions.getAttributeName(type) + " = "; + if (type == CKA_CLASS) { + return prefix + Functions.getObjectClassName(getLong()); + } else if (type == CKA_KEY_TYPE) { + return prefix + Functions.getKeyName(getLong()); + } else { + String s; + if (pValue instanceof char[]) { + s = new String((char[])pValue); + } else if (pValue instanceof byte[]) { + s = Functions.toHexString((byte[])pValue); + } else { + s = String.valueOf(pValue); + } + return prefix + s; + } + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_CCM_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_CCM_PARAMS.java new file mode 100644 index 0000000..95336d9 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_CCM_PARAMS.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * This class represents the necessary parameters required by + * the CKM_AES_CCM mechanism as defined in CK_CCM_PARAMS structure.

+ * PKCS#11 structure: + *

+ * typedef struct CK_CCM_PARAMS {
+ *   CK_ULONG ulDataLen;
+ *   CK_BYTE_PTR pNonce;
+ *   CK_ULONG ulNonceLen;
+ *   CK_BYTE_PTR pAAD;
+ *   CK_ULONG ulAADLen;
+ *   CK_ULONG ulMACLen;
+ * } CK_CCM_PARAMS;
+ * 
+ * + * @since 13 + */ +public class CK_CCM_PARAMS { + + private final long dataLen; + private final byte[] nonce; + private final byte[] aad; + private final long macLen; + + public CK_CCM_PARAMS(int tagLen, byte[] iv, byte[] aad, int dataLen) { + this.dataLen = dataLen; + this.nonce = iv; + this.aad = aad; + this.macLen = tagLen; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(Constants.INDENT); + sb.append("ulDataLen: "); + sb.append(dataLen); + sb.append(Constants.NEWLINE); + + sb.append(Constants.INDENT); + sb.append("iv: "); + sb.append(Functions.toHexString(nonce)); + sb.append(Constants.NEWLINE); + + sb.append(Constants.INDENT); + sb.append("aad: "); + sb.append(Functions.toHexString(aad)); + sb.append(Constants.NEWLINE); + + sb.append(Constants.INDENT); + sb.append("tagLen: "); + sb.append(macLen); + + return sb.toString(); + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_CREATEMUTEX.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_CREATEMUTEX.java new file mode 100644 index 0000000..5d76a63 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_CREATEMUTEX.java @@ -0,0 +1,68 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * interface CK_CREATEMUTEX. + * + * @author Karl Scheibelhofer <Karl.Scheibelhofer@iaik.at> + * @author Martin Schlaeffer <schlaeff@sbox.tugraz.at> + */ +public interface CK_CREATEMUTEX { + + /** + * Method CK_CREATEMUTEX + * + * @return The mutex (lock) object. + * @exception PKCS11Exception + */ + public Object CK_CREATEMUTEX() throws PKCS11Exception; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java new file mode 100644 index 0000000..48e28b6 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_C_INITIALIZE_ARGS.java @@ -0,0 +1,120 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_C_INITIALIZE_ARGS contains the optional arguments for the + * C_Initialize function.

+ * PKCS#11 structure: + *

+ * typedef struct CK_C_INITIALIZE_ARGS {  
+ *   CK_CREATEMUTEX CreateMutex;  
+ *   CK_DESTROYMUTEX DestroyMutex;  
+ *   CK_LOCKMUTEX LockMutex;  
+ *   CK_UNLOCKMUTEX UnlockMutex;  
+ *   CK_FLAGS flags;  
+ *   CK_VOID_PTR pReserved;  
+ * } CK_C_INITIALIZE_ARGS;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_C_INITIALIZE_ARGS { + + /** + * PKCS#11: + *
+     *   CK_CREATEMUTEX CreateMutex;
+     * 
+ */ + public CK_CREATEMUTEX CreateMutex; + + /** + * PKCS#11: + *
+     *   CK_DESTROYMUTEX DestroyMutex;
+     * 
+ */ + public CK_DESTROYMUTEX DestroyMutex; + + /** + * PKCS#11: + *
+     *   CK_LOCKMUTEX LockMutex;
+     * 
+ */ + public CK_LOCKMUTEX LockMutex; + + /** + * PKCS#11: + *
+     *   CK_UNLOCKMUTEX UnlockMutex;
+     * 
+ */ + public CK_UNLOCKMUTEX UnlockMutex; + + /** + * PKCS#11: + *
+     *   CK_FLAGS flags;
+     * 
+ */ + public long flags; + + /** + * PKCS#11: + *
+     *   CK_VOID_PTR pReserved;
+     * 
+ */ + public Object pReserved; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_DATE.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_DATE.java new file mode 100644 index 0000000..a31356d --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_DATE.java @@ -0,0 +1,137 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class .

+ * PKCS#11 structure: + *

+ * typedef struct CK_DATE {  
+ *   CK_CHAR year[4];  
+ *   CK_CHAR month[2];  
+ *   CK_CHAR day[2];  
+ * } CK_DATE;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_DATE implements Cloneable { + + /** + * PKCS#11: + *
+     *   CK_CHAR year[4];   - the year ("1900" - "9999")
+     * 
+ */ + public char[] year; /* the year ("1900" - "9999") */ + + /** + * PKCS#11: + *
+     *   CK_CHAR month[2];  - the month ("01" - "12")
+     * 
+ */ + public char[] month; /* the month ("01" - "12") */ + + /** + * PKCS#11: + *
+     *   CK_CHAR day[2];    - the day ("01" - "31")
+     * 
+ */ + public char[] day; /* the day ("01" - "31") */ + + public CK_DATE(char[] year, char[] month, char[] day) { + this.year = year; + this.month = month; + this.day = day; + } + + /** + * Create a (deep) clone of this object. + * + * @return A clone of this object. + */ + public Object clone() { + CK_DATE copy = null; + try { + copy = (CK_DATE) super.clone(); + } catch (CloneNotSupportedException cnse) { + // re-throw as RuntimeException + throw (RuntimeException) + (new RuntimeException("Clone error").initCause(cnse)); + } + copy.year = this.year.clone(); + copy.month = this.month.clone(); + copy.day = this.day.clone(); + + return copy; + } + + /** + * Returns the string representation of CK_DATE. + * + * @return the string representation of CK_DATE + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(new String(day)); + buffer.append('.'); + buffer.append(new String(month)); + buffer.append('.'); + buffer.append(new String(year)); + buffer.append(" (DD.MM.YYYY)"); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_DESTROYMUTEX.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_DESTROYMUTEX.java new file mode 100644 index 0000000..6dc1c96 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_DESTROYMUTEX.java @@ -0,0 +1,68 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * interface CK_DESTROYMUTEX.

+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public interface CK_DESTROYMUTEX { + + /** + * Method CK_DESTROYMUTEX + * + * @param pMutex The mutex (lock) object. + * @exception PKCS11Exception + */ + public void CK_DESTROYMUTEX(Object pMutex) throws PKCS11Exception; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java new file mode 100644 index 0000000..6f8393d --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_ECDH1_DERIVE_PARAMS provides the parameters to the + * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms.

+ * PKCS#11 structure: + *

+ * typedef struct CK_ECDH1_DERIVE_PARAMS {
+ *   CK_EC_KDF_TYPE kdf;
+ *   CK_ULONG ulSharedDataLen;
+ *   CK_BYTE_PTR pSharedData;
+ *   CK_ULONG ulPublicDataLen;
+ *   CK_BYTE_PTR pPublicData;
+ * } CK_ECDH1_DERIVE_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + */ +public class CK_ECDH1_DERIVE_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_EC_KDF_TYPE kdf;
+     * 
+ */ + public long kdf; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulSharedDataLen;
+     *   CK_BYTE_PTR pSharedData;
+     * 
+ */ + public byte[] pSharedData; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPublicDataLen;
+     *   CK_BYTE_PTR pPublicData;
+     * 
+ */ + public byte[] pPublicData; + + public CK_ECDH1_DERIVE_PARAMS(long kdf, byte[] pSharedData, byte[] pPublicData) { + this.kdf = kdf; + this.pSharedData = pSharedData; + this.pPublicData = pPublicData; + } + + /** + * Returns the string representation of CK_PKCS5_PBKD2_PARAMS. + * + * @return the string representation of CK_PKCS5_PBKD2_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("kdf: 0x"); + buffer.append(Functions.toFullHexString(kdf)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSharedDataLen: "); + buffer.append(pSharedData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSharedData: "); + buffer.append(Functions.toHexString(pSharedData)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicDataLen: "); + buffer.append(pPublicData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicData: "); + buffer.append(Functions.toHexString(pPublicData)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java new file mode 100644 index 0000000..2e49206 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_ECDH2_DERIVE_PARAMS.java @@ -0,0 +1,181 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_ECDH2_DERIVE_PARAMS provides the parameters to the + * CKM_ECMQV_DERIVE mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_ECDH2_DERIVE_PARAMS {
+ *   CK_EC_KDF_TYPE kdf;
+ *   CK_ULONG ulSharedDataLen;
+ *   CK_BYTE_PTR pSharedData;
+ *   CK_ULONG ulPublicDataLen;
+ *   CK_BYTE_PTR pPublicData;
+ *   CK_ULONG ulPrivateDataLen;
+ *   CK_OBJECT_HANDLE hPrivateData;
+ *   CK_ULONG ulPublicDataLen2;
+ *   CK_BYTE_PTR pPublicData2;
+ * } CK_ECDH2_DERIVE_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + */ +public class CK_ECDH2_DERIVE_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_EC_KDF_TYPE kdf;
+     * 
+ */ + public long kdf; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulSharedDataLen;
+     *   CK_BYTE_PTR pSharedData;
+     * 
+ */ + public byte[] pSharedData; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPublicDataLen;
+     *   CK_BYTE_PTR pPublicData;
+     * 
+ */ + public byte[] pPublicData; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPrivateDataLen;
+     * 
+ */ + public long ulPrivateDataLen; + + /** + * PKCS#11: + *
+     *   CK_OBJECT_HANDLE hPrivateData;
+     * 
+ */ + public long hPrivateData; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPublicDataLen2;
+     *   CK_BYTE_PTR pPublicData2;
+     * 
+ */ + public byte[] pPublicData2; + + /** + * Returns the string representation of CK_PKCS5_PBKD2_PARAMS. + * + * @return the string representation of CK_PKCS5_PBKD2_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("kdf: 0x"); + buffer.append(Functions.toFullHexString(kdf)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSharedDataLen: "); + buffer.append(pSharedData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSharedData: "); + buffer.append(Functions.toHexString(pSharedData)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicDataLen: "); + buffer.append(pPublicData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicData: "); + buffer.append(Functions.toHexString(pPublicData)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulPrivateDataLen: "); + buffer.append(ulPrivateDataLen); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hPrivateData: "); + buffer.append(hPrivateData); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicDataLen2: "); + buffer.append(pPublicData2.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicData2: "); + buffer.append(Functions.toHexString(pPublicData2)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_GCM_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_GCM_PARAMS.java new file mode 100644 index 0000000..ec0fd52 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_GCM_PARAMS.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * This class represents the necessary parameters required by + * the CKM_AES_GCM mechanism as defined in CK_GCM_PARAMS structure.

+ * PKCS#11 structure: + *

+ * typedef struct CK_GCM_PARAMS {
+ *    CK_BYTE_PTR       pIv;
+ *    CK_ULONG          ulIvLen;
+ *    CK_BYTE_PTR       pAAD;
+ *    CK_ULONG          ulAADLen;
+ *    CK_ULONG          ulTagBits;
+ * } CK_GCM_PARAMS;
+ * 
+ * + * @since 10 + */ +public class CK_GCM_PARAMS { + + private final byte[] iv; + private final byte[] aad; + private final long tagBits; + + public CK_GCM_PARAMS(int tagLenInBits, byte[] iv, byte[] aad) { + this.iv = iv; + this.aad = aad; + this.tagBits = tagLenInBits; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(Constants.INDENT); + sb.append("iv: "); + sb.append(Functions.toHexString(iv)); + sb.append(Constants.NEWLINE); + + sb.append(Constants.INDENT); + sb.append("aad: "); + sb.append(Functions.toHexString(aad)); + sb.append(Constants.NEWLINE); + + sb.append(Constants.INDENT); + sb.append("tagLen(in bits): "); + sb.append(tagBits); + + return sb.toString(); + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_INFO.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_INFO.java new file mode 100644 index 0000000..33f0117 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_INFO.java @@ -0,0 +1,164 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_INFO provides general information about Cryptoki.

+ * PKCS#11 structure: + *

+ *  typedef struct CK_INFO {  
+ *    CK_VERSION cryptokiVersion;  
+ *    CK_UTF8CHAR manufacturerID[32];  
+ *    CK_FLAGS flags;  
+ *    CK_UTF8CHAR libraryDescription[32];  
+ *    CK_VERSION libraryVersion;  
+ *  } CK_INFO;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_INFO { + + /** + * Cryptoki interface version number

+ * PKCS#11: + *

+     *   CK_VERSION cryptokiVersion;
+     * 
+ */ + public CK_VERSION cryptokiVersion; + + /** + * ID of the Cryptoki library manufacturer. must be blank + * padded - only the first 32 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR manufacturerID[32];
+     * 
+ */ + public char[] manufacturerID; + + /** + * bit flags reserved for future versions. must be zero

+ * PKCS#11: + *

+     *   CK_FLAGS flags;
+     * 
+ */ + public long flags; + + +/* libraryDescription and libraryVersion are new for v2.0 */ + + /** + * must be blank padded - only the first 32 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR libraryDescription[32];
+     * 
+ */ + public char[] libraryDescription; + + /** + * Cryptoki library version number

+ * PKCS#11: + *

+     *   CK_VERSION libraryVersion;
+     * 
+ */ + public CK_VERSION libraryVersion; + + public CK_INFO(CK_VERSION cryptoVer, char[] vendor, long flags, + char[] libDesc, CK_VERSION libVer) { + this.cryptokiVersion = cryptoVer; + this.manufacturerID = vendor; + this.flags = flags; + this.libraryDescription = libDesc; + this.libraryVersion = libVer; + } + + /** + * Returns the string representation of CK_INFO. + * + * @return the string representation of CK_INFO + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("cryptokiVersion: "); + buffer.append(cryptokiVersion.toString()); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("manufacturerID: "); + buffer.append(new String(manufacturerID)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("flags: "); + buffer.append(Functions.toBinaryString(flags)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("libraryDescription: "); + buffer.append(new String(libraryDescription)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("libraryVersion: "); + buffer.append(libraryVersion.toString()); + //buffer.append(Constants.NEWLINE); + + return buffer.toString() ; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_LOCKMUTEX.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_LOCKMUTEX.java new file mode 100644 index 0000000..e3a133e --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_LOCKMUTEX.java @@ -0,0 +1,68 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * interface CK_LOCKMUTEX

+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public interface CK_LOCKMUTEX { + + /** + * Method CK_LOCKMUTEX + * + * @param pMutex The mutex (lock) object to lock. + * @exception PKCS11Exception + */ + public void CK_LOCKMUTEX(Object pMutex) throws PKCS11Exception; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_MECHANISM.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_MECHANISM.java new file mode 100644 index 0000000..9ef42d4 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_MECHANISM.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.math.BigInteger; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * class CK_MECHANISM specifies a particular mechanism and any parameters it + * requires.

+ * PKCS#11 structure: + *

+ *  typedef struct CK_MECHANISM {  
+ *    CK_MECHANISM_TYPE mechanism;  
+ *    CK_VOID_PTR pParameter;  
+ *    CK_ULONG ulParameterLen;  
+ *  } CK_MECHANISM;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_MECHANISM { + + /** + * PKCS#11: + *
+     *   CK_MECHANISM_TYPE mechanism;
+     * 
+ */ + public long mechanism; + + /** + * PKCS#11: + *
+     *   CK_VOID_PTR pParameter;
+     *   CK_ULONG ulParameterLen;
+     * 
+ */ + public Object pParameter = null; + + // pointer to native CK_MECHANISM structure + // For mechanisms which have only mechanism id, the native structure + // can be freed right after init and this field will not be used. However, + // for mechanisms which have both mechanism id and parameters, it can + // only be freed after operation is finished. Thus, the native pointer + // will be stored here and then be explicitly freed by caller. + private long pHandle = 0L; + + public CK_MECHANISM(long mechanism) { + this.mechanism = mechanism; + } + + // We don't have a (long,Object) constructor to force type checking. + // This makes sure we don't accidentally pass a class that the native + // code cannot handle. + public CK_MECHANISM(long mechanism, byte[] pParameter) { + init(mechanism, pParameter); + } + + public CK_MECHANISM(long mechanism, BigInteger b) { + init(mechanism, sun.security.pkcs11.P11Util.getMagnitude(b)); + } + + public CK_MECHANISM(long mechanism, CK_VERSION version) { + init(mechanism, version); + } + + public CK_MECHANISM(long mechanism, CK_SSL3_MASTER_KEY_DERIVE_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_TLS12_MASTER_KEY_DERIVE_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_SSL3_KEY_MAT_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_TLS12_KEY_MAT_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_TLS_PRF_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_TLS_MAC_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_ECDH1_DERIVE_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, Long params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_AES_CTR_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_GCM_PARAMS params) { + init(mechanism, params); + } + + public CK_MECHANISM(long mechanism, CK_CCM_PARAMS params) { + init(mechanism, params); + } + + // For PSS. the parameter may be set multiple times, use the + // CK_MECHANISM(long) constructor and setParameter(CK_RSA_PKCS_PSS_PARAMS) + // methods instead of creating yet another constructor + public void setParameter(CK_RSA_PKCS_PSS_PARAMS params) { + assert(this.mechanism == CKM_RSA_PKCS_PSS); + assert(params != null); + if (this.pParameter != null && this.pParameter.equals(params)) { + return; + } + freeHandle(); + this.pParameter = params; + } + + public void freeHandle() { + if (this.pHandle != 0L) { + this.pHandle = PKCS11.freeMechanism(pHandle); + } + } + + private void init(long mechanism, Object pParameter) { + this.mechanism = mechanism; + this.pParameter = pParameter; + } + + /** + * Returns the string representation of CK_MECHANISM. + * + * @return the string representation of CK_MECHANISM + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("mechanism: "); + buffer.append(mechanism); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pParameter: "); + buffer.append(pParameter.toString()); + buffer.append(Constants.NEWLINE); + + /* + buffer.append(Constants.INDENT); + buffer.append("ulParameterLen: ??"); + buffer.append(Constants.NEWLINE); + */ + if (pHandle != 0L) { + buffer.append(Constants.INDENT); + buffer.append("pHandle: "); + buffer.append(pHandle); + buffer.append(Constants.NEWLINE); + } + return buffer.toString() ; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_MECHANISM_INFO.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_MECHANISM_INFO.java new file mode 100644 index 0000000..109acf0 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_MECHANISM_INFO.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.security.ProviderException; + +/** + * class CK_MECHANISM_INFO provides information about a particular mechanism. + *

+ * PKCS#11 structure: + *

+ * typedef struct CK_MECHANISM_INFO {  
+ *   CK_ULONG ulMinKeySize;  
+ *   CK_ULONG ulMaxKeySize;  
+ *   CK_FLAGS flags;  
+ * } CK_MECHANISM_INFO;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_MECHANISM_INFO { + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMinKeySize;
+     * 
+ */ + public long ulMinKeySize; + + // the integer version of ulMinKeySize for doing the actual range + // check in SunPKCS11 provider, defaults to 0 + public final int iMinKeySize; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMaxKeySize;
+     * 
+ */ + public long ulMaxKeySize; + + // the integer version of ulMaxKeySize for doing the actual range + // check in SunPKCS11 provider, defaults to Integer.MAX_VALUE + public final int iMaxKeySize; + + /** + * PKCS#11: + *
+     *   CK_FLAGS flags;
+     * 
+ */ + public long flags; + + public CK_MECHANISM_INFO(long minKeySize, long maxKeySize, + long flags) { + this.ulMinKeySize = minKeySize; + this.ulMaxKeySize = maxKeySize; + this.iMinKeySize = ((minKeySize < Integer.MAX_VALUE && minKeySize > 0)? + (int)minKeySize : 0); + this.iMaxKeySize = ((maxKeySize < Integer.MAX_VALUE && maxKeySize > 0)? + (int)maxKeySize : Integer.MAX_VALUE); + this.flags = flags; + } + + /** + * Returns the string representation of CK_MECHANISM_INFO. + * + * @return the string representation of CK_MECHANISM_INFO + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("ulMinKeySize: "); + buffer.append(String.valueOf(ulMinKeySize)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulMaxKeySize: "); + buffer.append(String.valueOf(ulMaxKeySize)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("flags: "); + buffer.append(String.valueOf(flags)); + buffer.append(" = "); + buffer.append(Functions.mechanismInfoFlagsToString(flags)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString() ; + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_NOTIFY.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_NOTIFY.java new file mode 100644 index 0000000..1dae3c3 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_NOTIFY.java @@ -0,0 +1,70 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * interface CK_NOTIFY.

+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public interface CK_NOTIFY { + + /** + * Method CK_NOTIFY + * + * @param hSession + * @param event + * @param pApplication + * @exception PKCS11Exception + */ + public void CK_NOTIFY(long hSession, long event, Object pApplication) throws PKCS11Exception; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_PBE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_PBE_PARAMS.java new file mode 100644 index 0000000..f9d70a5 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_PBE_PARAMS.java @@ -0,0 +1,142 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_PBE_PARAMS provides all of the necessary information required byte + * the CKM_PBE mechanisms and the CKM_PBA_SHA1_WITH_SHA1_HMAC mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_PBE_PARAMS {
+ *   CK_CHAR_PTR pInitVector;
+ *   CK_CHAR_PTR pPassword;
+ *   CK_ULONG ulPasswordLen;
+ *   CK_CHAR_PTR pSalt;
+ *   CK_ULONG ulSaltLen;
+ *   CK_ULONG ulIteration;
+ * } CK_PBE_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_PBE_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_CHAR_PTR pInitVector;
+     * 
+ */ + public char[] pInitVector; + + /** + * PKCS#11: + *
+     *   CK_CHAR_PTR pPassword;
+     *   CK_ULONG ulPasswordLen;
+     * 
+ */ + public char[] pPassword; + + /** + * PKCS#11: + *
+     *   CK_CHAR_PTR pSalt
+     *   CK_ULONG ulSaltLen;
+     * 
+ */ + public char[] pSalt; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulIteration;
+     * 
+ */ + public long ulIteration; + + /** + * Returns the string representation of CK_PBE_PARAMS. + * + * @return the string representation of CK_PBE_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("pInitVector: "); + buffer.append(pInitVector); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulPasswordLen: "); + buffer.append(pPassword.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulSaltLen: "); + buffer.append(pSalt.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSalt: "); + buffer.append(pSalt); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulIteration: "); + buffer.append(ulIteration); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java new file mode 100644 index 0000000..b0e91c9 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java @@ -0,0 +1,161 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_PKCS5_PBKD2_PARAMS provides the parameters to the CKM_PKCS5_PBKD2 + * mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_PKCS5_PBKD2_PARAMS {
+ *   CK_PKCS5_PBKD2_SALT_SOURCE_TYPE saltSource;
+ *   CK_VOID_PTR pSaltSourceData;
+ *   CK_ULONG ulSaltSourceDataLen;
+ *   CK_ULONG iterations;
+ *   CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ *   CK_VOID_PTR pPrfData;
+ *   CK_ULONG ulPrfDataLen;
+ * } CK_PKCS5_PBKD2_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_PKCS5_PBKD2_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+     * 
+ */ + public long saltSource; + + /** + * PKCS#11: + *
+     *   CK_VOID_PTR pSaltSourceData;
+     *   CK_ULONG ulSaltSourceDataLen;
+     * 
+ */ + public byte[] pSaltSourceData; + + /** + * PKCS#11: + *
+     *   CK_ULONG iterations;
+     * 
+ */ + public long iterations; + + /** + * PKCS#11: + *
+     *   CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+     * 
+ */ + public long prf; + + /** + * PKCS#11: + *
+     *   CK_VOID_PTR pPrfData;
+     *   CK_ULONG ulPrfDataLen;
+     * 
+ */ + public byte[] pPrfData; + + /** + * Returns the string representation of CK_PKCS5_PBKD2_PARAMS. + * + * @return the string representation of CK_PKCS5_PBKD2_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("saltSource: "); + buffer.append(saltSource); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSaltSourceData: "); + buffer.append(Functions.toHexString(pSaltSourceData)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulSaltSourceDataLen: "); + buffer.append(pSaltSourceData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("iterations: "); + buffer.append(iterations); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("prf: "); + buffer.append(prf); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPrfData: "); + buffer.append(Functions.toHexString(pPrfData)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulPrfDataLen: "); + buffer.append(pPrfData.length); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java new file mode 100644 index 0000000..0667f02 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS.java @@ -0,0 +1,143 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the + * CKM_RSA_PKCS_OAEP mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ *   CK_MECHANISM_TYPE hashAlg;
+ *   CK_RSA_PKCS_OAEP_MGF_TYPE mgf;
+ *   CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ *   CK_VOID_PTR pSourceData;
+ *   CK_ULONG ulSourceDataLen;
+ * } CK_RSA_PKCS_OAEP_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_RSA_PKCS_OAEP_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_MECHANISM_TYPE hashAlg;
+     * 
+ */ + public long hashAlg; + + /** + * PKCS#11: + *
+     *   CK_RSA_PKCS_OAEP_MGF_TYPE mgf;
+     * 
+ */ + public long mgf; + + /** + * PKCS#11: + *
+     *   CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+     * 
+ */ + public long source; + + /** + * PKCS#11: + *
+     *   CK_VOID_PTR pSourceData;
+     *   CK_ULONG ulSourceDataLen;
+     * 
+ */ + public byte[] pSourceData; + + //CK_ULONG ulSourceDataLen; + // ulSourceDataLen == pSourceData.length + + /** + * Returns the string representation of CK_RSA_PKCS_OAEP_PARAMS. + * + * @return the string representation of CK_RSA_PKCS_OAEP_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("hashAlg: "); + buffer.append(hashAlg); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("mgf: "); + buffer.append(mgf); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("source: "); + buffer.append(source); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSourceData: "); + buffer.append(pSourceData.toString()); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pSourceDataLen: "); + buffer.append(Functions.toHexString(pSourceData)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString() ; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java new file mode 100644 index 0000000..5b97a54 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.security.ProviderException; +import java.security.spec.PSSParameterSpec; +import java.security.spec.MGF1ParameterSpec; + +/** + * This class represents the necessary parameters required by the + * CKM_RSA_PKCS_PSS mechanism as defined in CK_RSA_PKCS_PSS_PARAMS structure.

+ * PKCS#11 structure: + *

+ * typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ *    CK_MECHANISM_TYPE    hashAlg;
+ *    CK_RSA_PKCS_MGF_TYPE mgf;
+ *    CK_ULONG             sLen;
+ * } CK_RSA_PKCS_PSS_PARAMS;
+ * 
+ * + * @since 13 + */ +public class CK_RSA_PKCS_PSS_PARAMS { + + private final long hashAlg; + private final long mgf; + private final long sLen; + + public CK_RSA_PKCS_PSS_PARAMS(String hashAlg, String mgfAlg, + String mgfHash, int sLen) { + this.hashAlg = Functions.getHashMechId(hashAlg); + if (!mgfAlg.equals("MGF1")) { + throw new ProviderException("Only MGF1 is supported"); + } + // no dash in PKCS#11 mechanism names + this.mgf = Functions.getMGFId("CKG_MGF1_" + hashAlg.replaceFirst("-", "")); + this.sLen = sLen; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof CK_RSA_PKCS_PSS_PARAMS)) { + return false; + } + + CK_RSA_PKCS_PSS_PARAMS other = (CK_RSA_PKCS_PSS_PARAMS) o; + return ((other.hashAlg == hashAlg) && + (other.mgf == mgf) && + (other.sLen == sLen)); + } + + @Override + public int hashCode() { + return (int)(hashAlg << 2 + mgf << 1 + sLen); + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("hashAlg: "); + buffer.append(Functions.toFullHexString(hashAlg)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("mgf: "); + buffer.append(Functions.toFullHexString(mgf)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("sLen(in bytes): "); + buffer.append(sLen); + + return buffer.toString(); + } +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SESSION_INFO.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SESSION_INFO.java new file mode 100644 index 0000000..e0f747a --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SESSION_INFO.java @@ -0,0 +1,142 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_SESSION_INFO provides information about a session.

+ * PKCS#11 structure: + *

+ * typedef struct CK_SESSION_INFO {  
+ *   CK_SLOT_ID slotID;  
+ *   CK_STATE state;  
+ *   CK_FLAGS flags;  
+ *   CK_ULONG ulDeviceError;  
+ * } CK_SESSION_INFO;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_SESSION_INFO { + + /** + * PKCS#11: + *
+     *   CK_SLOT_ID slotID;
+     * 
+ */ + public long slotID; + + /** + * PKCS#11: + *
+     *   CK_STATE state;
+     * 
+ */ + public long state; + + /** + * PKCS#11: + *
+     *   CK_FLAGS flags;
+     * 
+ */ + public long flags; /* see below */ + + /* ulDeviceError was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + /** + * PKCS#11: + *
+     *   CK_ULONG ulDeviceError;
+     * 
+ */ + public long ulDeviceError; /* device-dependent error code */ + + public CK_SESSION_INFO(long slotID, long state, + long flags, long ulDeviceError) { + this.slotID = slotID; + this.state = state; + this.flags = flags; + this.ulDeviceError = ulDeviceError; + } + + /** + * Returns the string representation of CK_SESSION_INFO. + * + * @return the string representation of CK_SESSION_INFO + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("slotID: "); + buffer.append(String.valueOf(slotID)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("state: "); + buffer.append(Functions.sessionStateToString(state)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("flags: "); + buffer.append(Functions.sessionInfoFlagsToString(flags)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulDeviceError: "); + buffer.append(Functions.toHexString(ulDeviceError)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString() ; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SLOT_INFO.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SLOT_INFO.java new file mode 100644 index 0000000..bd3b157 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SLOT_INFO.java @@ -0,0 +1,163 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_SLOT_INFO provides information about a slot.

+ * PKCS#11 structure: + *

+ *  typedef struct CK_SLOT_INFO {  
+ *    CK_UTF8CHAR slotDescription[64];  
+ *    CK_UTF8CHAR manufacturerID[32];  
+ *    CK_FLAGS flags;  
+ *    CK_VERSION hardwareVersion;  
+ *    CK_VERSION firmwareVersion;  
+ *  } CK_SLOT_INFO;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_SLOT_INFO { + + /* slotDescription and manufacturerID have been changed from + * CK_CHAR to CK_UTF8CHAR for v2.11. */ + + /** + * must be blank padded and only the first 64 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR slotDescription[64];
+     * 
+ */ + public char[] slotDescription; + + /** + * must be blank padded and only the first 32 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR manufacturerID[32];
+     * 
+ */ + public char[] manufacturerID; + + /** + * PKCS#11: + *
+     *   CK_FLAGS flags;
+     * 
+ */ + public long flags; + + /* hardwareVersion and firmwareVersion are new for v2.0 */ + /** + * version of hardware

+ * PKCS#11: + *

+     *   CK_VERSION hardwareVersion;
+     * 
+ */ + public CK_VERSION hardwareVersion; + + /** + * version of firmware

+ * PKCS#11: + *

+     *   CK_VERSION firmwareVersion;
+     * 
+ */ + public CK_VERSION firmwareVersion; + + public CK_SLOT_INFO(char[] slotDesc, char[] vendor, + long flags, CK_VERSION hwVer, CK_VERSION fwVer) { + this.slotDescription = slotDesc; + this.manufacturerID = vendor; + this.flags = flags; + this.hardwareVersion = hwVer; + this.firmwareVersion = fwVer; + } + + /** + * Returns the string representation of CK_SLOT_INFO. + * + * @return the string representation of CK_SLOT_INFO + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("slotDescription: "); + buffer.append(new String(slotDescription)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("manufacturerID: "); + buffer.append(new String(manufacturerID)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("flags: "); + buffer.append(Functions.slotInfoFlagsToString(flags)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hardwareVersion: "); + buffer.append(hardwareVersion.toString()); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("firmwareVersion: "); + buffer.append(firmwareVersion.toString()); + //buffer.append(Constants.NEWLINE); + + return buffer.toString() ; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java new file mode 100644 index 0000000..639f81a --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT.java @@ -0,0 +1,162 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_SSL3_KEY_MAT_OUT contains the resulting key handles and + * initialization vectors after performing a C_DeriveKey function with the + * CKM_SSL3_KEY_AND_MAC_DERIVE mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_SSL3_KEY_MAT_OUT {
+ *   CK_OBJECT_HANDLE hClientMacSecret;
+ *   CK_OBJECT_HANDLE hServerMacSecret;
+ *   CK_OBJECT_HANDLE hClientKey;
+ *   CK_OBJECT_HANDLE hServerKey;
+ *   CK_BYTE_PTR pIVClient;
+ *   CK_BYTE_PTR pIVServer;
+ * } CK_SSL3_KEY_MAT_OUT;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_SSL3_KEY_MAT_OUT{ + + /** + * PKCS#11: + *
+     *   CK_OBJECT_HANDLE hClientMacSecret;
+     * 
+ */ + public long hClientMacSecret; + + /** + * PKCS#11: + *
+     *   CK_OBJECT_HANDLE hServerMacSecret;
+     * 
+ */ + public long hServerMacSecret; + + /** + * PKCS#11: + *
+     *   CK_OBJECT_HANDLE hClientKey;
+     * 
+ */ + public long hClientKey; + + /** + * PKCS#11: + *
+     *   CK_OBJECT_HANDLE hServerKey;
+     * 
+ */ + public long hServerKey; + + /** + * PKCS#11: + *
+     *   CK_BYTE_PTR pIVClient;
+     * 
+ */ + public byte[] pIVClient; + + /** + * PKCS#11: + *
+     *   CK_BYTE_PTR pIVServer;
+     * 
+ */ + public byte[] pIVServer; + + /** + * Returns the string representation of CK_SSL3_KEY_MAT_OUT. + * + * @return the string representation of CK_SSL3_KEY_MAT_OUT + */ + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(Constants.INDENT); + buffer.append("hClientMacSecret: "); + buffer.append(hClientMacSecret); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hServerMacSecret: "); + buffer.append(hServerMacSecret); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hClientKey: "); + buffer.append(hClientKey); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hServerKey: "); + buffer.append(hServerKey); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pIVClient: "); + buffer.append(Functions.toHexString(pIVClient)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pIVServer: "); + buffer.append(Functions.toHexString(pIVServer)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java new file mode 100644 index 0000000..90741b4 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_PARAMS.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_SSL3_KEY_MAT_PARAMS provides the parameters to the + * CKM_SSL3_KEY_AND_MAC_DERIVE mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ *   CK_ULONG ulMacSizeInBits;
+ *   CK_ULONG ulKeySizeInBits;
+ *   CK_ULONG ulIVSizeInBits;
+ *   CK_BBOOL bIsExport;
+ *   CK_SSL3_RANDOM_DATA RandomInfo;
+ *   CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+ * } CK_SSL3_KEY_MAT_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_SSL3_KEY_MAT_PARAMS{ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMacSizeInBits;
+     * 
+ */ + public long ulMacSizeInBits; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulKeySizeInBits;
+     * 
+ */ + public long ulKeySizeInBits; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulIVSizeInBits;
+     * 
+ */ + public long ulIVSizeInBits; + + /** + * PKCS#11: + *
+     *   CK_BBOOL bIsExport;
+     * 
+ */ + public boolean bIsExport; + + /** + * PKCS#11: + *
+     *   CK_SSL3_RANDOM_DATA RandomInfo;
+     * 
+ */ + public CK_SSL3_RANDOM_DATA RandomInfo; + + /** + * PKCS#11: + *
+     *   CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+     * 
+ */ + public CK_SSL3_KEY_MAT_OUT pReturnedKeyMaterial; + + public CK_SSL3_KEY_MAT_PARAMS(int macSize, int keySize, int ivSize, boolean export, CK_SSL3_RANDOM_DATA random) { + ulMacSizeInBits = macSize; + ulKeySizeInBits = keySize; + ulIVSizeInBits = ivSize; + bIsExport = export; + RandomInfo = random; + pReturnedKeyMaterial = new CK_SSL3_KEY_MAT_OUT(); + if (ivSize != 0) { + int n = ivSize >> 3; + pReturnedKeyMaterial.pIVClient = new byte[n]; + pReturnedKeyMaterial.pIVServer = new byte[n]; + } + } + + /** + * Returns the string representation of CK_SSL3_KEY_MAT_PARAMS. + * + * @return the string representation of CK_SSL3_KEY_MAT_PARAMS + */ + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(Constants.INDENT); + buffer.append("ulMacSizeInBits: "); + buffer.append(ulMacSizeInBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulKeySizeInBits: "); + buffer.append(ulKeySizeInBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulIVSizeInBits: "); + buffer.append(ulIVSizeInBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("bIsExport: "); + buffer.append(bIsExport); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("RandomInfo: "); + buffer.append(RandomInfo); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pReturnedKeyMaterial: "); + buffer.append(pReturnedKeyMaterial); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java new file mode 100644 index 0000000..c645ae0 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_MASTER_KEY_DERIVE_PARAMS.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_SSL3_MASTER_KEY_DERIVE_PARAMS provides the parameters to the + * CKM_SSL3_MASTER_KEY_DERIVE mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ *   CK_SSL3_RANDOM_DATA RandomInfo;
+ *   CK_VERSION_PTR pVersion;
+ * } CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_SSL3_MASTER_KEY_DERIVE_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_SSL3_RANDOM_DATA RandomInfo;
+     * 
+ */ + public CK_SSL3_RANDOM_DATA RandomInfo; + + /** + * PKCS#11: + *
+     *   CK_VERSION_PTR pVersion;
+     * 
+ */ + public CK_VERSION pVersion; + + public CK_SSL3_MASTER_KEY_DERIVE_PARAMS(CK_SSL3_RANDOM_DATA random, CK_VERSION version) { + RandomInfo = random; + pVersion = version; + } + + /** + * Returns the string representation of CK_SSL3_MASTER_KEY_DERIVE_PARAMS. + * + * @return the string representation of CK_SSL3_MASTER_KEY_DERIVE_PARAMS + */ + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(Constants.INDENT); + buffer.append("RandomInfo: "); + buffer.append(RandomInfo); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pVersion: "); + buffer.append(pVersion); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java new file mode 100644 index 0000000..4a1c5a6 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_SSL3_RANDOM_DATA provides information about the random data of a + * client and a server in an SSL context. This class is used by both the + * CKM_SSL3_MASTER_KEY_DERIVE and the CKM_SSL3_KEY_AND_MAC_DERIVE mechanisms. + *

+ * PKCS#11 structure: + *

+ * typedef struct CK_SSL3_RANDOM_DATA {
+ *   CK_BYTE_PTR pClientRandom;
+ *   CK_ULONG ulClientRandomLen;
+ *   CK_BYTE_PTR pServerRandom;
+ *   CK_ULONG ulServerRandomLen;
+ * } CK_SSL3_RANDOM_DATA;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_SSL3_RANDOM_DATA { + + /** + * PKCS#11: + *
+     *   CK_BYTE_PTR pClientRandom;
+     *   CK_ULONG ulClientRandomLen;
+     * 
+ */ + public byte[] pClientRandom; + + /** + * PKCS#11: + *
+     *   CK_BYTE_PTR pServerRandom;
+     *   CK_ULONG ulServerRandomLen;
+     * 
+ */ + public byte[] pServerRandom; + + public CK_SSL3_RANDOM_DATA(byte[] clientRandom, byte[] serverRandom) { + pClientRandom = clientRandom; + pServerRandom = serverRandom; + } + + /** + * Returns the string representation of CK_SSL3_RANDOM_DATA. + * + * @return the string representation of CK_SSL3_RANDOM_DATA + */ + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(Constants.INDENT); + buffer.append("pClientRandom: "); + buffer.append(Functions.toHexString(pClientRandom)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulClientRandomLen: "); + buffer.append(pClientRandom.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pServerRandom: "); + buffer.append(Functions.toHexString(pServerRandom)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulServerRandomLen: "); + buffer.append(pServerRandom.length); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS12_KEY_MAT_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS12_KEY_MAT_PARAMS.java new file mode 100644 index 0000000..f42d6aa --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS12_KEY_MAT_PARAMS.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * CK_TLS12_KEY_MAT_PARAMS from PKCS#11 v2.40. + */ +public class CK_TLS12_KEY_MAT_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMacSizeInBits;
+     * 
+ */ + public long ulMacSizeInBits; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulKeySizeInBits;
+     * 
+ */ + public long ulKeySizeInBits; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulIVSizeInBits;
+     * 
+ */ + public long ulIVSizeInBits; + + /** + * PKCS#11: + *
+     *   CK_BBOOL bIsExport;
+     * 
+ */ + public boolean bIsExport; + + /** + * PKCS#11: + *
+     *   CK_SSL3_RANDOM_DATA RandomInfo;
+     * 
+ */ + public CK_SSL3_RANDOM_DATA RandomInfo; + + /** + * PKCS#11: + *
+     *   CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+     * 
+ */ + public CK_SSL3_KEY_MAT_OUT pReturnedKeyMaterial; + + /** + * PKCS#11: + *
+     *   CK_MECHANISM_TYPE prfHashMechanism;
+     * 
+ */ + public long prfHashMechanism; + + public CK_TLS12_KEY_MAT_PARAMS( + int macSize, int keySize, int ivSize, boolean export, + CK_SSL3_RANDOM_DATA random, long prfHashMechanism) { + ulMacSizeInBits = macSize; + ulKeySizeInBits = keySize; + ulIVSizeInBits = ivSize; + bIsExport = export; + RandomInfo = random; + pReturnedKeyMaterial = new CK_SSL3_KEY_MAT_OUT(); + if (ivSize != 0) { + int n = ivSize >> 3; + pReturnedKeyMaterial.pIVClient = new byte[n]; + pReturnedKeyMaterial.pIVServer = new byte[n]; + } + this.prfHashMechanism = prfHashMechanism; + } + + /** + * Returns the string representation of CK_TLS12_KEY_MAT_PARAMS. + * + * @return the string representation of CK_TLS12_KEY_MAT_PARAMS + */ + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(Constants.INDENT); + buffer.append("ulMacSizeInBits: "); + buffer.append(ulMacSizeInBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulKeySizeInBits: "); + buffer.append(ulKeySizeInBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulIVSizeInBits: "); + buffer.append(ulIVSizeInBits); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("bIsExport: "); + buffer.append(bIsExport); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("RandomInfo: "); + buffer.append(RandomInfo); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pReturnedKeyMaterial: "); + buffer.append(pReturnedKeyMaterial); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("prfHashMechanism: "); + buffer.append(prfHashMechanism); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS12_MASTER_KEY_DERIVE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS12_MASTER_KEY_DERIVE_PARAMS.java new file mode 100644 index 0000000..23e4e8b --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS12_MASTER_KEY_DERIVE_PARAMS.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * CK_TLS12_MASTER_KEY_DERIVE_PARAMS from PKCS#11 v2.40. + */ +public class CK_TLS12_MASTER_KEY_DERIVE_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_SSL3_RANDOM_DATA RandomInfo;
+     * 
+ */ + public CK_SSL3_RANDOM_DATA RandomInfo; + + /** + * PKCS#11: + *
+     *   CK_VERSION_PTR pVersion;
+     * 
+ */ + public CK_VERSION pVersion; + + /** + * PKCS#11: + *
+     *   CK_MECHANISM_TYPE prfHashMechanism;
+     * 
+ */ + public long prfHashMechanism; + + public CK_TLS12_MASTER_KEY_DERIVE_PARAMS( + CK_SSL3_RANDOM_DATA random, CK_VERSION version, + long prfHashMechanism) { + RandomInfo = random; + pVersion = version; + this.prfHashMechanism = prfHashMechanism; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS_MAC_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS_MAC_PARAMS.java new file mode 100644 index 0000000..520f5c5 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS_MAC_PARAMS.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * CK_TLS_MAC_PARAMS from PKCS#11 v2.40. + */ +public class CK_TLS_MAC_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_MECHANISM_TYPE prfMechanism;
+     * 
+ */ + public long prfMechanism; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMacLength;
+     * 
+ */ + public long ulMacLength; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulServerOrClient;
+     * 
+ */ + public long ulServerOrClient; + + public CK_TLS_MAC_PARAMS(long prfMechanism, + long ulMacLength, long ulServerOrClient) { + this.prfMechanism = prfMechanism; + this.ulMacLength = ulMacLength; + this.ulServerOrClient = ulServerOrClient; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java new file mode 100644 index 0000000..30f246b --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * CK_TLS_PRF_PARAMS from PKCS#11 v2.20. + * + * @author Andreas Sterbenz + * @since 1.6 + */ +public class CK_TLS_PRF_PARAMS { + + public byte[] pSeed; + public byte[] pLabel; + public byte[] pOutput; + + public CK_TLS_PRF_PARAMS(byte[] pSeed, byte[] pLabel, byte[] pOutput) { + this.pSeed = pSeed; + this.pLabel = pLabel; + this.pOutput = pOutput; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TOKEN_INFO.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TOKEN_INFO.java new file mode 100644 index 0000000..6fd071e --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_TOKEN_INFO.java @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_TOKEN_INFO provides information about a token.

+ * PKCS#11 structure: + *

+ * typedef struct CK_TOKEN_INFO {  
+ *   CK_UTF8CHAR label[32];  
+ *   CK_UTF8CHAR manufacturerID[32];  
+ *   CK_UTF8CHAR model[16];  
+ *   CK_CHAR serialNumber[16];  
+ *   CK_FLAGS flags;  
+ *   CK_ULONG ulMaxSessionCount;  
+ *   CK_ULONG ulSessionCount;  
+ *   CK_ULONG ulMaxRwSessionCount;  
+ *   CK_ULONG ulRwSessionCount;  
+ *   CK_ULONG ulMaxPinLen;  
+ *   CK_ULONG ulMinPinLen;  
+ *   CK_ULONG ulTotalPublicMemory;  
+ *   CK_ULONG ulFreePublicMemory;  
+ *   CK_ULONG ulTotalPrivateMemory;  
+ *   CK_ULONG ulFreePrivateMemory;  
+ *   CK_VERSION hardwareVersion;  
+ *   CK_VERSION firmwareVersion;  
+ *   CK_CHAR utcTime[16];  
+ * } CK_TOKEN_INFO;
+ *   
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_TOKEN_INFO { + + /* label, manufacturerID, and model have been changed from + * CK_CHAR to CK_UTF8CHAR for v2.11. */ + /** + * must be blank padded and only the first 32 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR label[32];
+     * 
+ */ + public char[] label; /* blank padded */ + + /** + * must be blank padded and only the first 32 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR manufacturerID[32];
+     * 
+ */ + public char[] manufacturerID; /* blank padded */ + + /** + * must be blank padded and only the first 16 chars will be used

+ * PKCS#11: + *

+     *   CK_UTF8CHAR model[16];
+     * 
+ */ + public char[] model; /* blank padded */ + + /** + * must be blank padded and only the first 16 chars will be used

+ * PKCS#11: + *

+     *   CK_CHAR serialNumber[16];
+     * 
+ */ + public char[] serialNumber; /* blank padded */ + + /** + * PKCS#11: + *
+     *   CK_FLAGS flags;
+     * 
+ */ + public long flags; /* see below */ + + /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, + * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been + * changed from CK_USHORT to CK_ULONG for v2.0 */ + /** + * PKCS#11: + *
+     *   CK_ULONG ulMaxSessionCount;
+     * 
+ */ + public long ulMaxSessionCount; /* max open sessions */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulSessionCount;
+     * 
+ */ + public long ulSessionCount; /* sess. now open */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMaxRwSessionCount;
+     * 
+ */ + public long ulMaxRwSessionCount; /* max R/W sessions */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulRwSessionCount;
+     * 
+ */ + public long ulRwSessionCount; /* R/W sess. now open */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMaxPinLen;
+     * 
+ */ + public long ulMaxPinLen; /* in bytes */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulMinPinLen;
+     * 
+ */ + public long ulMinPinLen; /* in bytes */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulTotalPublicMemory;
+     * 
+ */ + public long ulTotalPublicMemory; /* in bytes */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulFreePublicMemory;
+     * 
+ */ + public long ulFreePublicMemory; /* in bytes */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulTotalPrivateMemory;
+     * 
+ */ + public long ulTotalPrivateMemory; /* in bytes */ + + /** + * PKCS#11: + *
+     *   CK_ULONG ulFreePrivateMemory;
+     * 
+ */ + public long ulFreePrivateMemory; /* in bytes */ + + /* hardwareVersion, firmwareVersion, and time are new for + * v2.0 */ + /** + * PKCS#11: + *
+     *   CK_VERSION hardwareVersion;
+     * 
+ */ + public CK_VERSION hardwareVersion; /* version of hardware */ + + /** + * PKCS#11: + *
+     *   CK_VERSION firmwareVersion;
+     * 
+ */ + public CK_VERSION firmwareVersion; /* version of firmware */ + + /** + * only the first 16 chars will be used + * PKCS#11: + *
+     *   CK_CHAR utcTime[16];
+     * 
+ */ + public char[] utcTime; /* time */ + + public CK_TOKEN_INFO(char[] label, char[] vendor, char[] model, + char[] serialNo, long flags, + long sessionMax, long session, + long rwSessionMax, long rwSession, + long pinLenMax, long pinLenMin, + long totalPubMem, long freePubMem, + long totalPrivMem, long freePrivMem, + CK_VERSION hwVer, CK_VERSION fwVer, char[] utcTime) { + this.label = label; + this.manufacturerID = vendor; + this.model = model; + this.serialNumber = serialNo; + this.flags = flags; + this.ulMaxSessionCount = sessionMax; + this.ulSessionCount = session; + this.ulMaxRwSessionCount = rwSessionMax; + this.ulRwSessionCount = rwSession; + this.ulMaxPinLen = pinLenMax; + this.ulMinPinLen = pinLenMin; + this.ulTotalPublicMemory = totalPubMem; + this.ulFreePublicMemory = freePubMem; + this.ulTotalPrivateMemory = totalPrivMem; + this.ulFreePrivateMemory = freePrivMem; + this.hardwareVersion = hwVer; + this.firmwareVersion = fwVer; + this.utcTime = utcTime; + } + + /** + * Returns the string representation of CK_TOKEN_INFO. + * + * @return the string representation of CK_TOKEN_INFO + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("label: "); + buffer.append(new String(label)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("manufacturerID: "); + buffer.append(new String(manufacturerID)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("model: "); + buffer.append(new String(model)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("serialNumber: "); + buffer.append(new String(serialNumber)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("flags: "); + buffer.append(Functions.tokenInfoFlagsToString(flags)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulMaxSessionCount: "); + buffer.append((ulMaxSessionCount == PKCS11Constants.CK_EFFECTIVELY_INFINITE) + ? "CK_EFFECTIVELY_INFINITE" + : (ulMaxSessionCount == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulMaxSessionCount)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulSessionCount: "); + buffer.append((ulSessionCount == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulSessionCount)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulMaxRwSessionCount: "); + buffer.append((ulMaxRwSessionCount == PKCS11Constants.CK_EFFECTIVELY_INFINITE) + ? "CK_EFFECTIVELY_INFINITE" + : (ulMaxRwSessionCount == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulMaxRwSessionCount)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulRwSessionCount: "); + buffer.append((ulRwSessionCount == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulRwSessionCount)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulMaxPinLen: "); + buffer.append(String.valueOf(ulMaxPinLen)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulMinPinLen: "); + buffer.append(String.valueOf(ulMinPinLen)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulTotalPublicMemory: "); + buffer.append((ulTotalPublicMemory == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulTotalPublicMemory)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulFreePublicMemory: "); + buffer.append((ulFreePublicMemory == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulFreePublicMemory)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulTotalPrivateMemory: "); + buffer.append((ulTotalPrivateMemory == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulTotalPrivateMemory)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulFreePrivateMemory: "); + buffer.append((ulFreePrivateMemory == PKCS11Constants.CK_UNAVAILABLE_INFORMATION) + ? "CK_UNAVAILABLE_INFORMATION" + : String.valueOf(ulFreePrivateMemory)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hardwareVersion: "); + buffer.append(hardwareVersion.toString()); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("firmwareVersion: "); + buffer.append(firmwareVersion.toString()); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("utcTime: "); + buffer.append(new String(utcTime)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString() ; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java new file mode 100644 index 0000000..849ce71 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_UNLOCKMUTEX.java @@ -0,0 +1,68 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * interface CK_UNLOCKMUTEX

+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public interface CK_UNLOCKMUTEX { + + /** + * Method CK_UNLOCKMUTEX + * + * @param pMutex The mutex (lock) object to unlock. + * @exception PKCS11Exception + */ + public void CK_UNLOCKMUTEX(Object pMutex) throws PKCS11Exception; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_VERSION.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_VERSION.java new file mode 100644 index 0000000..5f0699c --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_VERSION.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_VERSION describes the version of a Cryptoki interface, a Cryptoki + * library, or an SSL implementation, or the hardware or firmware version of a + * slot or token.

+ * PKCS#11 structure: + *

+ * typedef struct CK_VERSION {  
+ *   CK_BYTE major;  
+ *   CK_BYTE minor;  
+ * } CK_VERSION;
+ * 
+ * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class CK_VERSION { + + /** + * PKCS#11: + *
+     *   CK_BYTE major;
+     * 
+ */ + public byte major; /* integer portion of version number */ + + /** + * PKCS#11: + *
+     *   CK_BYTE minor;
+     * 
+ */ + public byte minor; /* 1/100ths portion of version number */ + + public CK_VERSION(int major, int minor) { + this.major = (byte)major; + this.minor = (byte)minor; + } + + /** + * Returns the string representation of CK_VERSION. + * + * @return the string representation of CK_VERSION + */ + public String toString() { + StringBuilder buffer = new StringBuilder(); + + buffer.append(major & 0xff); + buffer.append('.'); + int m = minor & 0xff; + if (m < 10) { + buffer.append('0'); + } + buffer.append(m); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java new file mode 100644 index 0000000..8c2549c --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java @@ -0,0 +1,132 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the + * CKM_X9_42_DH_DERIVE mechanism.

+ * PKCS#11 structure: + *

+ * typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ *   CK_X9_42_DH_KDF_TYPE kdf;
+ *   CK_ULONG ulOtherInfoLen;
+ *   CK_BYTE_PTR pOtherInfo;
+ *   CK_ULONG ulPublicDataLen;
+ *   CK_BYTE_PTR pPublicData;
+ * } CK_X9_42_DH1_DERIVE_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + */ +public class CK_X9_42_DH1_DERIVE_PARAMS { + + /** + * PKCS#11: + *
+    *   CK_X9_42_DH_KDF_TYPE kdf;
+     * 
+ */ + public long kdf; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulOtherInfoLen;
+     *   CK_BYTE_PTR pOtherInfo;
+     * 
+ */ + public byte[] pOtherInfo; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPublicDataLen;
+     *   CK_BYTE_PTR pPublicData;
+     * 
+ */ + public byte[] pPublicData; + + /** + * Returns the string representation of CK_PKCS5_PBKD2_PARAMS. + * + * @return the string representation of CK_PKCS5_PBKD2_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("kdf: 0x"); + buffer.append(Functions.toFullHexString(kdf)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pOtherInfoLen: "); + buffer.append(pOtherInfo.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pOtherInfo: "); + buffer.append(Functions.toHexString(pOtherInfo)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicDataLen: "); + buffer.append(pPublicData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicData: "); + buffer.append(Functions.toHexString(pPublicData)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java new file mode 100644 index 0000000..3cb5150 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/CK_X9_42_DH2_DERIVE_PARAMS.java @@ -0,0 +1,181 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * class CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the + * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE mechanisms.

+ * PKCS#11 structure: + *

+ * typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ *   CK_X9_42_DH_KDF_TYPE kdf;
+ *   CK_ULONG ulOtherInfoLen;
+ *   CK_BYTE_PTR pOtherInfo;
+ *   CK_ULONG ulPublicDataLen;
+ *   CK_BYTE_PTR pPublicData;
+ *   CK_ULONG ulPrivateDataLen;
+ *   CK_OBJECT_HANDLE hPrivateData;
+ *   CK_ULONG ulPublicDataLen2;
+ *   CK_BYTE_PTR pPublicData2;
+ * } CK_X9_42_DH2_DERIVE_PARAMS;
+ * 
+ * + * @author Karl Scheibelhofer + */ +public class CK_X9_42_DH2_DERIVE_PARAMS { + + /** + * PKCS#11: + *
+     *   CK_X9_42_DH_KDF_TYPE kdf;
+     * 
+ */ + public long kdf; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulOtherInfoLen;
+     *   CK_BYTE_PTR pOtherInfo;
+     * 
+ */ + public byte[] pOtherInfo; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPublicDataLen;
+     *   CK_BYTE_PTR pPublicData;
+     * 
+ */ + public byte[] pPublicData; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPrivateDataLen;
+     * 
+ */ + public long ulPrivateDataLen; + + /** + * PKCS#11: + *
+     *   CK_OBJECT_HANDLE hPrivateData;
+     * 
+ */ + public long hPrivateData; + + /** + * PKCS#11: + *
+     *   CK_ULONG ulPublicDataLen2;
+     *   CK_BYTE_PTR pPublicData2;
+     * 
+ */ + public byte[] pPublicData2; + + /** + * Returns the string representation of CK_PKCS5_PBKD2_PARAMS. + * + * @return the string representation of CK_PKCS5_PBKD2_PARAMS + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(Constants.INDENT); + buffer.append("kdf: 0x"); + buffer.append(Functions.toFullHexString(kdf)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pOtherInfoLen: "); + buffer.append(pOtherInfo.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pOtherInfo: "); + buffer.append(Functions.toHexString(pOtherInfo)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicDataLen: "); + buffer.append(pPublicData.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicData: "); + buffer.append(Functions.toHexString(pPublicData)); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("ulPrivateDataLen: "); + buffer.append(ulPrivateDataLen); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("hPrivateData: "); + buffer.append(hPrivateData); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicDataLen2: "); + buffer.append(pPublicData2.length); + buffer.append(Constants.NEWLINE); + + buffer.append(Constants.INDENT); + buffer.append("pPublicData2: "); + buffer.append(Functions.toHexString(pPublicData2)); + //buffer.append(Constants.NEWLINE); + + return buffer.toString(); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/Constants.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/Constants.java new file mode 100644 index 0000000..f49c180 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/Constants.java @@ -0,0 +1,65 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + + +/** + * This class holds only final static member variables that are constants + * in this package. + * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class Constants { + + public static final String NEWLINE = System.getProperty("line.separator"); + + public static final String INDENT = " "; + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/Functions.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/Functions.java new file mode 100644 index 0000000..9c36412 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/Functions.java @@ -0,0 +1,1357 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.math.BigInteger; + +import java.util.*; + +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * This class contains only static methods. It is the place for all functions + * that are used by several classes in this package. + * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + */ +public class Functions { + + // maps between ids and their names, forward and reverse + // ids are stored as Integers to save space + // since only the lower 32 bits are ever used anyway + + // mechanisms (CKM_*) + private static final Map mechNames = + new HashMap(); + + private static final Map mechIds = + new HashMap(); + + private static final Map hashMechIds = + new HashMap(); + + // key types (CKK_*) + private static final Map keyNames = + new HashMap(); + + private static final Map keyIds = + new HashMap(); + + // attributes (CKA_*) + private static final Map attributeNames = + new HashMap(); + + private static final Map attributeIds = + new HashMap(); + + // object classes (CKO_*) + private static final Map objectClassNames = + new HashMap(); + + private static final Map objectClassIds = + new HashMap(); + + // MGFs (CKG_*) + private static final Map mgfNames = + new HashMap(); + + private static final Map mgfIds = + new HashMap(); + + /** + * For converting numbers to their hex presentation. + */ + private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); + + /** + * Converts a long value to a hexadecimal String of length 16. Includes + * leading zeros if necessary. + * + * @param value The long value to be converted. + * @return The hexadecimal string representation of the long value. + */ + public static String toFullHexString(long value) { + long currentValue = value; + StringBuffer stringBuffer = new StringBuffer(16); + for(int j = 0; j < 16; j++) { + int currentDigit = (int) currentValue & 0xf; + stringBuffer.append(HEX_DIGITS[currentDigit]); + currentValue >>>= 4; + } + + return stringBuffer.reverse().toString(); + } + + /** + * Converts a int value to a hexadecimal String of length 8. Includes + * leading zeros if necessary. + * + * @param value The int value to be converted. + * @return The hexadecimal string representation of the int value. + */ + public static String toFullHexString(int value) { + int currentValue = value; + StringBuffer stringBuffer = new StringBuffer(8); + for(int i = 0; i < 8; i++) { + int currentDigit = currentValue & 0xf; + stringBuffer.append(HEX_DIGITS[currentDigit]); + currentValue >>>= 4; + } + + return stringBuffer.reverse().toString(); + } + + /** + * converts a long value to a hexadecimal String + * + * @param value the long value to be converted + * @return the hexadecimal string representation of the long value + */ + public static String toHexString(long value) { + return Long.toHexString(value); + } + + /** + * Converts a byte array to a hexadecimal String. Each byte is presented by + * its two digit hex-code; 0x0A -> "0a", 0x00 -> "00". No leading "0x" is + * included in the result. + * + * @param value the byte array to be converted + * @return the hexadecimal string representation of the byte array + */ + public static String toHexString(byte[] value) { + if (value == null) { + return null; + } + + StringBuffer buffer = new StringBuffer(2 * value.length); + int single; + + for (int i = 0; i < value.length; i++) { + single = value[i] & 0xFF; + + if (single < 0x10) { + buffer.append('0'); + } + + buffer.append(Integer.toString(single, 16)); + } + + return buffer.toString(); + } + + /** + * converts a long value to a binary String + * + * @param value the long value to be converted + * @return the binary string representation of the long value + */ + public static String toBinaryString(long value) { + return Long.toString(value, 2); + } + + /** + * converts a byte array to a binary String + * + * @param value the byte array to be converted + * @return the binary string representation of the byte array + */ + public static String toBinaryString(byte[] value) { + BigInteger helpBigInteger = new BigInteger(1, value); + + return helpBigInteger.toString(2); + } + + private static class Flags { + private final long[] flagIds; + private final String[] flagNames; + Flags(long[] flagIds, String[] flagNames) { + if (flagIds.length != flagNames.length) { + throw new AssertionError("Array lengths do not match"); + } + this.flagIds = flagIds; + this.flagNames = flagNames; + } + String toString(long val) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (int i = 0; i < flagIds.length; i++) { + if ((val & flagIds[i]) != 0) { + if (first == false) { + sb.append(" | "); + } + sb.append(flagNames[i]); + first = false; + } + } + return sb.toString(); + } + } + + private static final Flags slotInfoFlags = new Flags(new long[] { + CKF_TOKEN_PRESENT, + CKF_REMOVABLE_DEVICE, + CKF_HW_SLOT, + }, new String[] { + "CKF_TOKEN_PRESENT", + "CKF_REMOVABLE_DEVICE", + "CKF_HW_SLOT", + }); + + /** + * converts the long value flags to a SlotInfoFlag string + * + * @param flags the flags to be converted + * @return the SlotInfoFlag string representation of the flags + */ + public static String slotInfoFlagsToString(long flags) { + return slotInfoFlags.toString(flags); + } + + private static final Flags tokenInfoFlags = new Flags(new long[] { + CKF_RNG, + CKF_WRITE_PROTECTED, + CKF_LOGIN_REQUIRED, + CKF_USER_PIN_INITIALIZED, + CKF_RESTORE_KEY_NOT_NEEDED, + CKF_CLOCK_ON_TOKEN, + CKF_PROTECTED_AUTHENTICATION_PATH, + CKF_DUAL_CRYPTO_OPERATIONS, + CKF_TOKEN_INITIALIZED, + CKF_SECONDARY_AUTHENTICATION, + CKF_USER_PIN_COUNT_LOW, + CKF_USER_PIN_FINAL_TRY, + CKF_USER_PIN_LOCKED, + CKF_USER_PIN_TO_BE_CHANGED, + CKF_SO_PIN_COUNT_LOW, + CKF_SO_PIN_FINAL_TRY, + CKF_SO_PIN_LOCKED, + CKF_SO_PIN_TO_BE_CHANGED, + }, new String[] { + "CKF_RNG", + "CKF_WRITE_PROTECTED", + "CKF_LOGIN_REQUIRED", + "CKF_USER_PIN_INITIALIZED", + "CKF_RESTORE_KEY_NOT_NEEDED", + "CKF_CLOCK_ON_TOKEN", + "CKF_PROTECTED_AUTHENTICATION_PATH", + "CKF_DUAL_CRYPTO_OPERATIONS", + "CKF_TOKEN_INITIALIZED", + "CKF_SECONDARY_AUTHENTICATION", + "CKF_USER_PIN_COUNT_LOW", + "CKF_USER_PIN_FINAL_TRY", + "CKF_USER_PIN_LOCKED", + "CKF_USER_PIN_TO_BE_CHANGED", + "CKF_SO_PIN_COUNT_LOW", + "CKF_SO_PIN_FINAL_TRY", + "CKF_SO_PIN_LOCKED", + "CKF_SO_PIN_TO_BE_CHANGED", + }); + + /** + * converts long value flags to a TokenInfoFlag string + * + * @param flags the flags to be converted + * @return the TokenInfoFlag string representation of the flags + */ + public static String tokenInfoFlagsToString(long flags) { + return tokenInfoFlags.toString(flags); + } + + private static final Flags sessionInfoFlags = new Flags(new long[] { + CKF_RW_SESSION, + CKF_SERIAL_SESSION, + }, new String[] { + "CKF_RW_SESSION", + "CKF_SERIAL_SESSION", + }); + + /** + * converts the long value flags to a SessionInfoFlag string + * + * @param flags the flags to be converted + * @return the SessionInfoFlag string representation of the flags + */ + public static String sessionInfoFlagsToString(long flags) { + return sessionInfoFlags.toString(flags); + } + + /** + * converts the long value state to a SessionState string + * + * @param state the state to be converted + * @return the SessionState string representation of the state + */ + public static String sessionStateToString(long state) { + String name; + + if (state == CKS_RO_PUBLIC_SESSION) { + name = "CKS_RO_PUBLIC_SESSION"; + } else if (state == CKS_RO_USER_FUNCTIONS) { + name = "CKS_RO_USER_FUNCTIONS"; + } else if (state == CKS_RW_PUBLIC_SESSION) { + name = "CKS_RW_PUBLIC_SESSION"; + } else if (state == CKS_RW_USER_FUNCTIONS) { + name = "CKS_RW_USER_FUNCTIONS"; + } else if (state == CKS_RW_SO_FUNCTIONS) { + name = "CKS_RW_SO_FUNCTIONS"; + } else { + name = "ERROR: unknown session state 0x" + toFullHexString(state); + } + + return name; + } + + private static final Flags mechanismInfoFlags = new Flags(new long[] { + CKF_HW, + CKF_MESSAGE_ENCRYPT, + CKF_MESSAGE_DECRYPT, + CKF_MESSAGE_SIGN, + CKF_MESSAGE_VERIFY, + CKF_MULTI_MESSAGE, + CKF_FIND_OBJECTS, + CKF_ENCRYPT, + CKF_DECRYPT, + CKF_DIGEST, + CKF_SIGN, + CKF_SIGN_RECOVER, + CKF_VERIFY, + CKF_VERIFY_RECOVER, + CKF_GENERATE, + CKF_GENERATE_KEY_PAIR, + CKF_WRAP, + CKF_UNWRAP, + CKF_DERIVE, + CKF_EC_F_P, + CKF_EC_F_2M, + CKF_EC_ECPARAMETERS, + CKF_EC_OID, + CKF_EC_UNCOMPRESS, + CKF_EC_COMPRESS, + CKF_EC_CURVENAME, + CKF_EXTENSION, + }, new String[] { + "CKF_HW", + "CKF_MESSAGE_ENCRYPT", + "CKF_MESSAGE_DECRYPT", + "CKF_MESSAGE_SIGN", + "CKF_MESSAGE_VERIFY", + "CKF_MULTI_MESSAGE", + "CKF_FIND_OBJECTS", + "CKF_ENCRYPT", + "CKF_DECRYPT", + "CKF_DIGEST", + "CKF_SIGN", + "CKF_SIGN_RECOVER", + "CKF_VERIFY", + "CKF_VERIFY_RECOVER", + "CKF_GENERATE", + "CKF_GENERATE_KEY_PAIR", + "CKF_WRAP", + "CKF_UNWRAP", + "CKF_DERIVE", + "CKF_EC_F_P", + "CKF_EC_F_2M", + "CKF_EC_ECPARAMETERS", + "CKF_EC_OID", + "CKF_EC_UNCOMPRESS", + "CKF_EC_COMPRESS", + "CKF_EC_CURVENAME", + "CKF_EXTENSION", + }); + + /** + * converts the long value flags to a MechanismInfoFlag string + * + * @param flags the flags to be converted + * @return the MechanismInfoFlag string representation of the flags + */ + public static String mechanismInfoFlagsToString(long flags) { + return mechanismInfoFlags.toString(flags); + } + + private static String getName(Map nameMap, long id) { + String name = null; + if ((id >>> 32) == 0) { + name = nameMap.get(Integer.valueOf((int)id)); + } + if (name == null) { + if ((id & CKM_VENDOR_DEFINED) != 0) { + name = "(Vendor-Specific) 0x" + toFullHexString(id); + } else { + name = "(Unknown) 0x" + toFullHexString(id); + } + } + return name; + } + + public static long getId(Map idMap, String name) { + Integer mech = idMap.get(name); + if (mech == null) { + throw new IllegalArgumentException("Unknown name " + name); + } + return mech.intValue() & 0xffffffffL; + } + + public static String getMechanismName(long id) { + return getName(mechNames, id); + } + + public static long getMechanismId(String name) { + return getId(mechIds, name); + } + + public static String getKeyName(long id) { + return getName(keyNames, id); + } + + public static long getKeyId(String name) { + return getId(keyIds, name); + } + + public static String getAttributeName(long id) { + return getName(attributeNames, id); + } + + public static long getAttributeId(String name) { + return getId(attributeIds, name); + } + + public static String getObjectClassName(long id) { + return getName(objectClassNames, id); + } + + public static long getObjectClassId(String name) { + return getId(objectClassIds, name); + } + + public static long getHashMechId(String name) { + return hashMechIds.get(name); + } + + public static String getMGFName(long id) { + return getName(mgfNames, id); + } + + public static long getMGFId(String name) { + return getId(mgfIds, name); + } + + /** + * Check the given arrays for equalitiy. This method considers both arrays as + * equal, if both are null or both have the same length and + * contain exactly the same char values. + * + * @param array1 The first array. + * @param array2 The second array. + * @return True, if both arrays are null or both have the same + * length and contain exactly the same char values. False, otherwise. + * @preconditions + * @postconditions + */ + private static boolean equals(char[] array1, char[] array2) { + return Arrays.equals(array1, array2); + } + + /** + * Check the given dates for equalitiy. This method considers both dates as + * equal, if both are null or both contain exactly the same char + * values. + * + * @param date1 The first date. + * @param date2 The second date. + * @return True, if both dates are null or both contain the same + * char values. False, otherwise. + * @preconditions + * @postconditions + */ + public static boolean equals(CK_DATE date1, CK_DATE date2) { + boolean equal = false; + + if (date1 == date2) { + equal = true; + } else if ((date1 != null) && (date2 != null)) { + equal = equals(date1.year, date2.year) + && equals(date1.month, date2.month) + && equals(date1.day, date2.day); + } else { + equal = false; + } + + return equal ; + } + + /** + * Calculate a hash code for the given byte array. + * + * @param array The byte array. + * @return A hash code for the given array. + * @preconditions + * @postconditions + */ + public static int hashCode(byte[] array) { + int hash = 0; + + if (array != null) { + for (int i = 0; (i < 4) && (i < array.length); i++) { + hash ^= (0xFF & array[i]) << ((i%4) << 3); + } + } + + return hash ; + } + + /** + * Calculate a hash code for the given char array. + * + * @param array The char array. + * @return A hash code for the given array. + * @preconditions + * @postconditions + */ + public static int hashCode(char[] array) { + int hash = 0; + + if (array != null) { + for (int i = 0; (i < 4) && (i < array.length); i++) { + hash ^= (0xFFFF & array[i]) << ((i%2) << 4); + } + } + + return hash ; + } + + /** + * Calculate a hash code for the given date object. + * + * @param date The date object. + * @return A hash code for the given date. + * @preconditions + * @postconditions + */ + public static int hashCode(CK_DATE date) { + int hash = 0; + + if (date != null) { + if (date.year.length == 4) { + hash ^= (0xFFFF & date.year[0]) << 16; + hash ^= 0xFFFF & date.year[1]; + hash ^= (0xFFFF & date.year[2]) << 16; + hash ^= 0xFFFF & date.year[3]; + } + if (date.month.length == 2) { + hash ^= (0xFFFF & date.month[0]) << 16; + hash ^= 0xFFFF & date.month[1]; + } + if (date.day.length == 2) { + hash ^= (0xFFFF & date.day[0]) << 16; + hash ^= 0xFFFF & date.day[1]; + } + } + + return hash ; + } + + private static void addMapping(Map nameMap, + Map idMap, long id, String name) { + if ((id >>> 32) != 0) { + throw new AssertionError("Id has high bits set: " + id + ", " + name); + } + Integer intId = Integer.valueOf((int)id); + if (nameMap.put(intId, name) != null) { + throw new AssertionError("Duplicate id: " + id + ", " + name); + } + if (idMap.put(name, intId) != null) { + throw new AssertionError("Duplicate name: " + id + ", " + name); + } + } + + private static void addMech(long id, String name) { + addMapping(mechNames, mechIds, id, name); + } + + private static void addKeyType(long id, String name) { + addMapping(keyNames, keyIds, id, name); + } + + private static void addAttribute(long id, String name) { + addMapping(attributeNames, attributeIds, id, name); + } + + private static void addObjectClass(long id, String name) { + addMapping(objectClassNames, objectClassIds, id, name); + } + + private static void addHashMech(long id, String... names) { + for (String n : names) { + hashMechIds.put(n, id); + } + } + + private static void addMGF(long id, String name) { + addMapping(mgfNames, mgfIds, id, name); + } + + // The ordering here follows the PKCS11Constants class + static { + addMech(CKM_RSA_PKCS_KEY_PAIR_GEN, "CKM_RSA_PKCS_KEY_PAIR_GEN"); + addMech(CKM_RSA_PKCS, "CKM_RSA_PKCS"); + addMech(CKM_RSA_9796, "CKM_RSA_9796"); + addMech(CKM_RSA_X_509, "CKM_RSA_X_509"); + addMech(CKM_MD2_RSA_PKCS, "CKM_MD2_RSA_PKCS"); + addMech(CKM_MD5_RSA_PKCS, "CKM_MD5_RSA_PKCS"); + addMech(CKM_SHA1_RSA_PKCS, "CKM_SHA1_RSA_PKCS"); + addMech(CKM_RIPEMD128_RSA_PKCS, "CKM_RIPEMD128_RSA_PKCS"); + addMech(CKM_RIPEMD160_RSA_PKCS, "CKM_RIPEMD160_RSA_PKCS"); + addMech(CKM_RSA_PKCS_OAEP, "CKM_RSA_PKCS_OAEP"); + addMech(CKM_RSA_X9_31_KEY_PAIR_GEN, "CKM_RSA_X9_31_KEY_PAIR_GEN"); + addMech(CKM_RSA_X9_31, "CKM_RSA_X9_31"); + addMech(CKM_SHA1_RSA_X9_31, "CKM_SHA1_RSA_X9_31"); + addMech(CKM_RSA_PKCS_PSS, "CKM_RSA_PKCS_PSS"); + addMech(CKM_SHA1_RSA_PKCS_PSS, "CKM_SHA1_RSA_PKCS_PSS"); + addMech(CKM_DSA_KEY_PAIR_GEN, "CKM_DSA_KEY_PAIR_GEN"); + addMech(CKM_DSA, "CKM_DSA"); + addMech(CKM_DSA_SHA1, "CKM_DSA_SHA1"); + addMech(CKM_DSA_SHA224, "CKM_DSA_SHA224"); + addMech(CKM_DSA_SHA256, "CKM_DSA_SHA256"); + addMech(CKM_DSA_SHA384, "CKM_DSA_SHA384"); + addMech(CKM_DSA_SHA512, "CKM_DSA_SHA512"); + addMech(CKM_DSA_SHA3_224, "CKM_DSA_SHA3_224"); + addMech(CKM_DSA_SHA3_256, "CKM_DSA_SHA3_256"); + addMech(CKM_DSA_SHA3_384, "CKM_DSA_SHA3_384"); + addMech(CKM_DSA_SHA3_512, "CKM_DSA_SHA3_512"); + + addMech(CKM_DH_PKCS_KEY_PAIR_GEN, "CKM_DH_PKCS_KEY_PAIR_GEN"); + addMech(CKM_DH_PKCS_DERIVE, "CKM_DH_PKCS_DERIVE"); + addMech(CKM_X9_42_DH_KEY_PAIR_GEN, "CKM_X9_42_DH_KEY_PAIR_GEN"); + addMech(CKM_X9_42_DH_DERIVE, "CKM_X9_42_DH_DERIVE"); + addMech(CKM_X9_42_DH_HYBRID_DERIVE, "CKM_X9_42_DH_HYBRID_DERIVE"); + addMech(CKM_X9_42_MQV_DERIVE, "CKM_X9_42_MQV_DERIVE"); + + addMech(CKM_SHA256_RSA_PKCS, "CKM_SHA256_RSA_PKCS"); + addMech(CKM_SHA384_RSA_PKCS, "CKM_SHA384_RSA_PKCS"); + addMech(CKM_SHA512_RSA_PKCS, "CKM_SHA512_RSA_PKCS"); + addMech(CKM_SHA256_RSA_PKCS_PSS, "CKM_SHA256_RSA_PKCS_PSS"); + addMech(CKM_SHA384_RSA_PKCS_PSS, "CKM_SHA384_RSA_PKCS_PSS"); + addMech(CKM_SHA512_RSA_PKCS_PSS, "CKM_SHA512_RSA_PKCS_PSS"); + addMech(CKM_SHA224_RSA_PKCS, "CKM_SHA224_RSA_PKCS"); + addMech(CKM_SHA224_RSA_PKCS_PSS, "CKM_SHA224_RSA_PKCS_PSS"); + + addMech(CKM_SHA512_224, "CKM_SHA512_224"); + addMech(CKM_SHA512_224_HMAC, "CKM_SHA512_224_HMAC"); + addMech(CKM_SHA512_224_HMAC_GENERAL, "CKM_SHA512_224_HMAC_GENERAL"); + addMech(CKM_SHA512_224_KEY_DERIVATION, "CKM_SHA512_224_KEY_DERIVATION"); + addMech(CKM_SHA512_256, "CKM_SHA512_256"); + addMech(CKM_SHA512_256_HMAC, "CKM_SHA512_256_HMAC"); + addMech(CKM_SHA512_256_HMAC_GENERAL, "CKM_SHA512_256_HMAC_GENERAL"); + addMech(CKM_SHA512_256_KEY_DERIVATION, "CKM_SHA512_256_KEY_DERIVATION"); + addMech(CKM_SHA512_T, "CKM_SHA512_T"); + addMech(CKM_SHA512_T_HMAC, "CKM_SHA512_T_HMAC"); + addMech(CKM_SHA512_T_HMAC_GENERAL, "CKM_SHA512_T_HMAC_GENERAL"); + addMech(CKM_SHA512_T_KEY_DERIVATION, "CKM_SHA512_T_KEY_DERIVATION"); + + addMech(CKM_SHA3_256_RSA_PKCS, "CKM_SHA3_256_RSA_PKCS"); + addMech(CKM_SHA3_384_RSA_PKCS, "CKM_SHA3_384_RSA_PKCS"); + addMech(CKM_SHA3_512_RSA_PKCS, "CKM_SHA3_512_RSA_PKCS"); + addMech(CKM_SHA3_256_RSA_PKCS_PSS, "CKM_SHA3_256_RSA_PKCS_PSS"); + addMech(CKM_SHA3_384_RSA_PKCS_PSS, "CKM_SHA3_384_RSA_PKCS_PSS"); + addMech(CKM_SHA3_512_RSA_PKCS_PSS, "CKM_SHA3_512_RSA_PKCS_PSS"); + addMech(CKM_SHA3_224_RSA_PKCS, "CKM_SHA3_224_RSA_PKCS"); + addMech(CKM_SHA3_224_RSA_PKCS_PSS, "CKM_SHA3_224_RSA_PKCS_PSS"); + + addMech(CKM_RC2_KEY_GEN, "CKM_RC2_KEY_GEN"); + addMech(CKM_RC2_ECB, "CKM_RC2_ECB"); + addMech(CKM_RC2_CBC, "CKM_RC2_CBC"); + addMech(CKM_RC2_MAC, "CKM_RC2_MAC"); + addMech(CKM_RC2_MAC_GENERAL, "CKM_RC2_MAC_GENERAL"); + addMech(CKM_RC2_CBC_PAD, "CKM_RC2_CBC_PAD"); + addMech(CKM_RC4_KEY_GEN, "CKM_RC4_KEY_GEN"); + addMech(CKM_RC4, "CKM_RC4"); + addMech(CKM_DES_KEY_GEN, "CKM_DES_KEY_GEN"); + addMech(CKM_DES_ECB, "CKM_DES_ECB"); + addMech(CKM_DES_CBC, "CKM_DES_CBC"); + addMech(CKM_DES_MAC, "CKM_DES_MAC"); + addMech(CKM_DES_MAC_GENERAL, "CKM_DES_MAC_GENERAL"); + addMech(CKM_DES_CBC_PAD, "CKM_DES_CBC_PAD"); + addMech(CKM_DES2_KEY_GEN, "CKM_DES2_KEY_GEN"); + addMech(CKM_DES3_KEY_GEN, "CKM_DES3_KEY_GEN"); + addMech(CKM_DES3_ECB, "CKM_DES3_ECB"); + addMech(CKM_DES3_CBC, "CKM_DES3_CBC"); + addMech(CKM_DES3_MAC, "CKM_DES3_MAC"); + addMech(CKM_DES3_MAC_GENERAL, "CKM_DES3_MAC_GENERAL"); + addMech(CKM_DES3_CBC_PAD, "CKM_DES3_CBC_PAD"); + addMech(CKM_DES3_CMAC_GENERAL, "CKM_DES3_CMAC_GENERAL"); + addMech(CKM_DES3_CMAC, "CKM_DES3_CMAC"); + + addMech(CKM_CDMF_KEY_GEN, "CKM_CDMF_KEY_GEN"); + addMech(CKM_CDMF_ECB, "CKM_CDMF_ECB"); + addMech(CKM_CDMF_CBC, "CKM_CDMF_CBC"); + addMech(CKM_CDMF_MAC, "CKM_CDMF_MAC"); + addMech(CKM_CDMF_MAC_GENERAL, "CKM_CDMF_MAC_GENERAL"); + addMech(CKM_CDMF_CBC_PAD, "CKM_CDMF_CBC_PAD"); + + addMech(CKM_DES_OFB64, "CKM_DES_OFB64"); + addMech(CKM_DES_OFB8, "CKM_DES_OFB8"); + addMech(CKM_DES_CFB64, "CKM_DES_CFB64"); + addMech(CKM_DES_CFB8, "CKM_DES_CFB8"); + + addMech(CKM_MD2, "CKM_MD2"); + addMech(CKM_MD2_HMAC, "CKM_MD2_HMAC"); + addMech(CKM_MD2_HMAC_GENERAL, "CKM_MD2_HMAC_GENERAL"); + addMech(CKM_MD5, "CKM_MD5"); + addMech(CKM_MD5_HMAC, "CKM_MD5_HMAC"); + addMech(CKM_MD5_HMAC_GENERAL, "CKM_MD5_HMAC_GENERAL"); + addMech(CKM_SHA_1, "CKM_SHA_1"); + addMech(CKM_SHA_1_HMAC, "CKM_SHA_1_HMAC"); + addMech(CKM_SHA_1_HMAC_GENERAL, "CKM_SHA_1_HMAC_GENERAL"); + addMech(CKM_RIPEMD128, "CKM_RIPEMD128"); + addMech(CKM_RIPEMD128_HMAC, "CKM_RIPEMD128_HMAC"); + addMech(CKM_RIPEMD128_HMAC_GENERAL, "CKM_RIPEMD128_HMAC_GENERAL"); + addMech(CKM_RIPEMD160, "CKM_RIPEMD160"); + addMech(CKM_RIPEMD160_HMAC, "CKM_RIPEMD160_HMAC"); + addMech(CKM_RIPEMD160_HMAC_GENERAL, "CKM_RIPEMD160_HMAC_GENERAL"); + addMech(CKM_SHA256, "CKM_SHA256"); + addMech(CKM_SHA256_HMAC, "CKM_SHA256_HMAC"); + addMech(CKM_SHA256_HMAC_GENERAL, "CKM_SHA256_HMAC_GENERAL"); + addMech(CKM_SHA224, "CKM_SHA224"); + addMech(CKM_SHA224_HMAC, "CKM_SHA224_HMAC"); + addMech(CKM_SHA224_HMAC_GENERAL, "CKM_SHA224_HMAC_GENERAL"); + addMech(CKM_SHA384, "CKM_SHA384"); + addMech(CKM_SHA384_HMAC, "CKM_SHA384_HMAC"); + addMech(CKM_SHA384_HMAC_GENERAL, "CKM_SHA384_HMAC_GENERAL"); + addMech(CKM_SHA512, "CKM_SHA512"); + addMech(CKM_SHA512_HMAC, "CKM_SHA512_HMAC"); + addMech(CKM_SHA512_HMAC_GENERAL, "CKM_SHA512_HMAC_GENERAL"); + + addMech(CKM_SECURID_KEY_GEN, "CKM_SECURID_KEY_GEN"); + addMech(CKM_SECURID, "CKM_SECURID"); + addMech(CKM_HOTP_KEY_GEN, "CKM_HOTP_KEY_GEN"); + addMech(CKM_HOTP, "CKM_HOTP"); + addMech(CKM_ACTI, "CKM_ACTI"); + addMech(CKM_ACTI_KEY_GEN, "CKM_ACTI_KEY_GEN"); + + addMech(CKM_SHA3_256, "CKM_SHA3_256"); + addMech(CKM_SHA3_256_HMAC, "CKM_SHA3_256_HMAC"); + addMech(CKM_SHA3_256_HMAC_GENERAL, "CKM_SHA3_256_HMAC_GENERAL"); + addMech(CKM_SHA3_256_KEY_GEN, "CKM_SHA3_256_KEY_GEN"); + addMech(CKM_SHA3_224, "CKM_SHA3_224"); + addMech(CKM_SHA3_224_HMAC, "CKM_SHA3_224_HMAC"); + addMech(CKM_SHA3_224_HMAC_GENERAL, "CKM_SHA3_224_HMAC_GENERAL"); + addMech(CKM_SHA3_224_KEY_GEN, "CKM_SHA3_224_KEY_GEN"); + addMech(CKM_SHA3_384, "CKM_SHA3_384"); + addMech(CKM_SHA3_384_HMAC, "CKM_SHA3_384_HMAC"); + addMech(CKM_SHA3_384_HMAC_GENERAL, "CKM_SHA3_384_HMAC_GENERAL"); + addMech(CKM_SHA3_384_KEY_GEN, "CKM_SHA3_384_KEY_GEN"); + addMech(CKM_SHA3_512, "CKM_SHA3_512"); + addMech(CKM_SHA3_512_HMAC, "CKM_SHA3_512_HMAC"); + addMech(CKM_SHA3_512_HMAC_GENERAL, "CKM_SHA3_512_HMAC_GENERAL"); + addMech(CKM_SHA3_512_KEY_GEN, "CKM_SHA3_512_KEY_GEN"); + + addMech(CKM_CAST_KEY_GEN, "CKM_CAST_KEY_GEN"); + addMech(CKM_CAST_ECB, "CKM_CAST_ECB"); + addMech(CKM_CAST_CBC, "CKM_CAST_CBC"); + addMech(CKM_CAST_MAC, "CKM_CAST_MAC"); + addMech(CKM_CAST_MAC_GENERAL, "CKM_CAST_MAC_GENERAL"); + addMech(CKM_CAST_CBC_PAD, "CKM_CAST_CBC_PAD"); + addMech(CKM_CAST3_KEY_GEN, "CKM_CAST3_KEY_GEN"); + addMech(CKM_CAST3_ECB, "CKM_CAST3_ECB"); + addMech(CKM_CAST3_CBC, "CKM_CAST3_CBC"); + addMech(CKM_CAST3_MAC, "CKM_CAST3_MAC"); + addMech(CKM_CAST3_MAC_GENERAL, "CKM_CAST3_MAC_GENERAL"); + addMech(CKM_CAST3_CBC_PAD, "CKM_CAST3_CBC_PAD"); + addMech(CKM_CAST128_KEY_GEN, "CKM_CAST128_KEY_GEN"); + addMech(CKM_CAST128_ECB, "CKM_CAST128_ECB"); + addMech(CKM_CAST128_CBC, "CKM_CAST128_CBC"); + addMech(CKM_CAST128_MAC, "CKM_CAST128_MAC"); + addMech(CKM_CAST128_MAC_GENERAL, "CKM_CAST128_MAC_GENERAL"); + addMech(CKM_CAST128_CBC_PAD, "CKM_CAST128_CBC_PAD"); + addMech(CKM_RC5_KEY_GEN, "CKM_RC5_KEY_GEN"); + addMech(CKM_RC5_ECB, "CKM_RC5_ECB"); + addMech(CKM_RC5_CBC, "CKM_RC5_CBC"); + addMech(CKM_RC5_MAC, "CKM_RC5_MAC"); + addMech(CKM_RC5_MAC_GENERAL, "CKM_RC5_MAC_GENERAL"); + addMech(CKM_RC5_CBC_PAD, "CKM_RC5_CBC_PAD"); + addMech(CKM_IDEA_KEY_GEN, "CKM_IDEA_KEY_GEN"); + addMech(CKM_IDEA_ECB, "CKM_IDEA_ECB"); + addMech(CKM_IDEA_CBC, "CKM_IDEA_CBC"); + addMech(CKM_IDEA_MAC, "CKM_IDEA_MAC"); + addMech(CKM_IDEA_MAC_GENERAL, "CKM_IDEA_MAC_GENERAL"); + addMech(CKM_IDEA_CBC_PAD, "CKM_IDEA_CBC_PAD"); + addMech(CKM_GENERIC_SECRET_KEY_GEN, "CKM_GENERIC_SECRET_KEY_GEN"); + addMech(CKM_CONCATENATE_BASE_AND_KEY, "CKM_CONCATENATE_BASE_AND_KEY"); + addMech(CKM_CONCATENATE_BASE_AND_DATA, "CKM_CONCATENATE_BASE_AND_DATA"); + addMech(CKM_CONCATENATE_DATA_AND_BASE, "CKM_CONCATENATE_DATA_AND_BASE"); + addMech(CKM_XOR_BASE_AND_DATA, "CKM_XOR_BASE_AND_DATA"); + addMech(CKM_EXTRACT_KEY_FROM_KEY, "CKM_EXTRACT_KEY_FROM_KEY"); + addMech(CKM_SSL3_PRE_MASTER_KEY_GEN, "CKM_SSL3_PRE_MASTER_KEY_GEN"); + addMech(CKM_SSL3_MASTER_KEY_DERIVE, "CKM_SSL3_MASTER_KEY_DERIVE"); + addMech(CKM_SSL3_KEY_AND_MAC_DERIVE, "CKM_SSL3_KEY_AND_MAC_DERIVE"); + addMech(CKM_SSL3_MASTER_KEY_DERIVE_DH, "CKM_SSL3_MASTER_KEY_DERIVE_DH"); + addMech(CKM_TLS_PRE_MASTER_KEY_GEN, "CKM_TLS_PRE_MASTER_KEY_GEN"); + addMech(CKM_TLS_MASTER_KEY_DERIVE, "CKM_TLS_MASTER_KEY_DERIVE"); + addMech(CKM_TLS_KEY_AND_MAC_DERIVE, "CKM_TLS_KEY_AND_MAC_DERIVE"); + addMech(CKM_TLS_MASTER_KEY_DERIVE_DH, "CKM_TLS_MASTER_KEY_DERIVE_DH"); + addMech(CKM_TLS_PRF, "CKM_TLS_PRF"); + addMech(CKM_SSL3_MD5_MAC, "CKM_SSL3_MD5_MAC"); + addMech(CKM_SSL3_SHA1_MAC, "CKM_SSL3_SHA1_MAC"); + + addMech(CKM_MD5_KEY_DERIVATION, "CKM_MD5_KEY_DERIVATION"); + addMech(CKM_MD2_KEY_DERIVATION, "CKM_MD2_KEY_DERIVATION"); + addMech(CKM_SHA1_KEY_DERIVATION, "CKM_SHA1_KEY_DERIVATION"); + addMech(CKM_SHA256_KEY_DERIVATION, "CKM_SHA256_KEY_DERIVATION"); + addMech(CKM_SHA384_KEY_DERIVATION, "CKM_SHA384_KEY_DERIVATION"); + addMech(CKM_SHA512_KEY_DERIVATION, "CKM_SHA512_KEY_DERIVATION"); + addMech(CKM_SHA224_KEY_DERIVATION, "CKM_SHA224_KEY_DERIVATION"); + addMech(CKM_SHA3_256_KEY_DERIVATION, "CKM_SHA3_256_KEY_DERIVATION"); + addMech(CKM_SHA3_224_KEY_DERIVATION, "CKM_SHA3_224_KEY_DERIVATION"); + addMech(CKM_SHA3_384_KEY_DERIVATION, "CKM_SHA3_384_KEY_DERIVATION"); + addMech(CKM_SHA3_512_KEY_DERIVATION, "CKM_SHA3_512_KEY_DERIVATION"); + addMech(CKM_SHAKE_128_KEY_DERIVATION, "CKM_SHAKE_128_KEY_DERIVATION"); + addMech(CKM_SHAKE_256_KEY_DERIVATION, "CKM_SHAKE_256_KEY_DERIVATION"); + + addMech(CKM_PBE_MD2_DES_CBC, "CKM_PBE_MD2_DES_CBC"); + addMech(CKM_PBE_MD5_DES_CBC, "CKM_PBE_MD5_DES_CBC"); + addMech(CKM_PBE_MD5_CAST_CBC, "CKM_PBE_MD5_CAST_CBC"); + addMech(CKM_PBE_MD5_CAST3_CBC, "CKM_PBE_MD5_CAST3_CBC"); + addMech(CKM_PBE_MD5_CAST128_CBC, "CKM_PBE_MD5_CAST128_CBC"); + addMech(CKM_PBE_SHA1_CAST128_CBC, "CKM_PBE_SHA1_CAST128_CBC"); + addMech(CKM_PBE_SHA1_RC4_128, "CKM_PBE_SHA1_RC4_128"); + addMech(CKM_PBE_SHA1_RC4_40, "CKM_PBE_SHA1_RC4_40"); + addMech(CKM_PBE_SHA1_DES3_EDE_CBC, "CKM_PBE_SHA1_DES3_EDE_CBC"); + addMech(CKM_PBE_SHA1_DES2_EDE_CBC, "CKM_PBE_SHA1_DES2_EDE_CBC"); + addMech(CKM_PBE_SHA1_RC2_128_CBC, "CKM_PBE_SHA1_RC2_128_CBC"); + addMech(CKM_PBE_SHA1_RC2_40_CBC, "CKM_PBE_SHA1_RC2_40_CBC"); + addMech(CKM_PKCS5_PBKD2, "CKM_PKCS5_PBKD2"); + addMech(CKM_PBA_SHA1_WITH_SHA1_HMAC, "CKM_PBA_SHA1_WITH_SHA1_HMAC"); + + addMech(CKM_WTLS_PRE_MASTER_KEY_GEN, "CKM_WTLS_PRE_MASTER_KEY_GEN"); + addMech(CKM_WTLS_MASTER_KEY_DERIVE, "CKM_WTLS_MASTER_KEY_DERIVE"); + addMech(CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC, + "CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC"); + addMech(CKM_WTLS_PRF, "CKM_WTLS_PRF"); + addMech(CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE, + "CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE"); + addMech(CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE, + "CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE"); + addMech(CKM_TLS10_MAC_SERVER, "CKM_TLS10_MAC_SERVER"); + addMech(CKM_TLS10_MAC_CLIENT, "CKM_TLS10_MAC_CLIENT"); + addMech(CKM_TLS12_MAC, "CKM_TLS12_MAC"); + addMech(CKM_TLS12_KDF, "CKM_TLS12_KDF"); + addMech(CKM_TLS12_MASTER_KEY_DERIVE, "CKM_TLS12_MASTER_KEY_DERIVE"); + addMech(CKM_TLS12_KEY_AND_MAC_DERIVE, "CKM_TLS12_KEY_AND_MAC_DERIVE"); + addMech(CKM_TLS12_MASTER_KEY_DERIVE_DH, "CKM_TLS12_MASTER_KEY_DERIVE_DH"); + addMech(CKM_TLS12_KEY_SAFE_DERIVE, "CKM_TLS12_KEY_SAFE_DERIVE"); + addMech(CKM_TLS_MAC, "CKM_TLS_MAC"); + addMech(CKM_TLS_KDF, "CKM_TLS_KDF"); + + addMech(CKM_KEY_WRAP_LYNKS, "CKM_KEY_WRAP_LYNKS"); + addMech(CKM_KEY_WRAP_SET_OAEP, "CKM_KEY_WRAP_SET_OAEP"); + + addMech(CKM_CMS_SIG, "CKM_CMS_SIG"); + addMech(CKM_KIP_DERIVE, "CKM_KIP_DERIVE"); + addMech(CKM_KIP_WRAP, "CKM_KIP_WRAP"); + addMech(CKM_KIP_MAC, "CKM_KIP_MAC"); + addMech(CKM_CAMELLIA_KEY_GEN, "CKM_CAMELLIA_KEY_GEN"); + addMech(CKM_CAMELLIA_ECB, "CKM_CAMELLIA_ECB"); + addMech(CKM_CAMELLIA_CBC, "CKM_CAMELLIA_CBC"); + addMech(CKM_CAMELLIA_MAC, "CKM_CAMELLIA_MAC"); + addMech(CKM_CAMELLIA_MAC_GENERAL, "CKM_CAMELLIA_MAC_GENERAL"); + addMech(CKM_CAMELLIA_CBC_PAD, "CKM_CAMELLIA_CBC_PAD"); + addMech(CKM_CAMELLIA_ECB_ENCRYPT_DATA, "CKM_CAMELLIA_ECB_ENCRYPT_DATA"); + addMech(CKM_CAMELLIA_CBC_ENCRYPT_DATA, "CKM_CAMELLIA_CBC_ENCRYPT_DATA"); + addMech(CKM_CAMELLIA_CTR, "CKM_CAMELLIA_CTR"); + + addMech(CKM_ARIA_KEY_GEN, "CKM_ARIA_KEY_GEN"); + addMech(CKM_ARIA_ECB, "CKM_ARIA_ECB"); + addMech(CKM_ARIA_CBC, "CKM_ARIA_CBC"); + addMech(CKM_ARIA_MAC, "CKM_ARIA_MAC"); + addMech(CKM_ARIA_MAC_GENERAL, "CKM_ARIA_MAC_GENERAL"); + addMech(CKM_ARIA_CBC_PAD, "CKM_ARIA_CBC_PAD"); + addMech(CKM_ARIA_ECB_ENCRYPT_DATA, "CKM_ARIA_ECB_ENCRYPT_DATA"); + addMech(CKM_ARIA_CBC_ENCRYPT_DATA, "CKM_ARIA_CBC_ENCRYPT_DATA"); + + addMech(CKM_SEED_KEY_GEN, "CKM_SEED_KEY_GEN"); + addMech(CKM_SEED_ECB, "CKM_SEED_ECB"); + addMech(CKM_SEED_CBC, "CKM_SEED_CBC"); + addMech(CKM_SEED_MAC, "CKM_SEED_MAC"); + addMech(CKM_SEED_MAC_GENERAL, "CKM_SEED_MAC_GENERAL"); + addMech(CKM_SEED_CBC_PAD, "CKM_SEED_CBC_PAD"); + addMech(CKM_SEED_ECB_ENCRYPT_DATA, "CKM_SEED_ECB_ENCRYPT_DATA"); + addMech(CKM_SEED_CBC_ENCRYPT_DATA, "CKM_SEED_CBC_ENCRYPT_DATA"); + + addMech(CKM_SKIPJACK_KEY_GEN, "CKM_SKIPJACK_KEY_GEN"); + addMech(CKM_SKIPJACK_ECB64, "CKM_SKIPJACK_ECB64"); + addMech(CKM_SKIPJACK_CBC64, "CKM_SKIPJACK_CBC64"); + addMech(CKM_SKIPJACK_OFB64, "CKM_SKIPJACK_OFB64"); + addMech(CKM_SKIPJACK_CFB64, "CKM_SKIPJACK_CFB64"); + addMech(CKM_SKIPJACK_CFB32, "CKM_SKIPJACK_CFB32"); + addMech(CKM_SKIPJACK_CFB16, "CKM_SKIPJACK_CFB16"); + addMech(CKM_SKIPJACK_CFB8, "CKM_SKIPJACK_CFB8"); + addMech(CKM_SKIPJACK_WRAP, "CKM_SKIPJACK_WRAP"); + addMech(CKM_SKIPJACK_PRIVATE_WRAP, "CKM_SKIPJACK_PRIVATE_WRAP"); + addMech(CKM_SKIPJACK_RELAYX, "CKM_SKIPJACK_RELAYX"); + addMech(CKM_KEA_KEY_PAIR_GEN, "CKM_KEA_KEY_PAIR_GEN"); + addMech(CKM_KEA_KEY_DERIVE, "CKM_KEA_KEY_DERIVE"); + addMech(CKM_FORTEZZA_TIMESTAMP, "CKM_FORTEZZA_TIMESTAMP"); + addMech(CKM_BATON_KEY_GEN, "CKM_BATON_KEY_GEN"); + addMech(CKM_BATON_ECB128, "CKM_BATON_ECB128"); + addMech(CKM_BATON_ECB96, "CKM_BATON_ECB96"); + addMech(CKM_BATON_CBC128, "CKM_BATON_CBC128"); + addMech(CKM_BATON_COUNTER, "CKM_BATON_COUNTER"); + addMech(CKM_BATON_SHUFFLE, "CKM_BATON_SHUFFLE"); + addMech(CKM_BATON_WRAP, "CKM_BATON_WRAP"); + addMech(CKM_EC_KEY_PAIR_GEN, "CKM_EC_KEY_PAIR_GEN"); + addMech(CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS, + "CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS"); + + addMech(CKM_ECDSA, "CKM_ECDSA"); + addMech(CKM_ECDSA_SHA1, "CKM_ECDSA_SHA1"); + addMech(CKM_ECDSA_SHA224, "CKM_ECDSA_SHA224"); + addMech(CKM_ECDSA_SHA256, "CKM_ECDSA_SHA256"); + addMech(CKM_ECDSA_SHA384, "CKM_ECDSA_SHA384"); + addMech(CKM_ECDSA_SHA512, "CKM_ECDSA_SHA512"); + addMech(CKM_ECDSA_SHA3_224, "CKM_ECDSA_SHA3_224"); + addMech(CKM_ECDSA_SHA3_256, "CKM_ECDSA_SHA3_256"); + addMech(CKM_ECDSA_SHA3_384, "CKM_ECDSA_SHA3_384"); + addMech(CKM_ECDSA_SHA3_512, "CKM_ECDSA_SHA3_512"); + + addMech(CKM_ECDH1_DERIVE, "CKM_ECDH1_DERIVE"); + addMech(CKM_ECDH1_COFACTOR_DERIVE, "CKM_ECDH1_COFACTOR_DERIVE"); + addMech(CKM_ECMQV_DERIVE, "CKM_ECMQV_DERIVE"); + addMech(CKM_ECDH_AES_KEY_WRAP, "CKM_ECDH_AES_KEY_WRAP"); + addMech(CKM_RSA_AES_KEY_WRAP, "CKM_RSA_AES_KEY_WRAP"); + addMech(CKM_EC_EDWARDS_KEY_PAIR_GEN, "CKM_EC_EDWARDS_KEY_PAIR_GEN"); + addMech(CKM_EC_MONTGOMERY_KEY_PAIR_GEN, + "CKM_EC_MONTGOMERY_KEY_PAIR_GEN"); + addMech(CKM_EDDSA, "CKM_EDDSA"); + + addMech(CKM_JUNIPER_KEY_GEN, "CKM_JUNIPER_KEY_GEN"); + addMech(CKM_JUNIPER_ECB128, "CKM_JUNIPER_ECB128"); + addMech(CKM_JUNIPER_CBC128, "CKM_JUNIPER_CBC128"); + addMech(CKM_JUNIPER_COUNTER, "CKM_JUNIPER_COUNTER"); + addMech(CKM_JUNIPER_SHUFFLE, "CKM_JUNIPER_SHUFFLE"); + addMech(CKM_JUNIPER_WRAP, "CKM_JUNIPER_WRAP"); + addMech(CKM_FASTHASH, "CKM_FASTHASH"); + addMech(CKM_AES_XTS, "CKM_AES_XTS"); + addMech(CKM_AES_XTS_KEY_GEN, "CKM_AES_XTS_KEY_GEN"); + + addMech(CKM_AES_KEY_GEN, "CKM_AES_KEY_GEN"); + addMech(CKM_AES_ECB, "CKM_AES_ECB"); + addMech(CKM_AES_CBC, "CKM_AES_CBC"); + addMech(CKM_AES_MAC, "CKM_AES_MAC"); + addMech(CKM_AES_MAC_GENERAL, "CKM_AES_MAC_GENERAL"); + addMech(CKM_AES_CBC_PAD, "CKM_AES_CBC_PAD"); + addMech(CKM_AES_CTR, "CKM_AES_CTR"); + addMech(CKM_AES_GCM, "CKM_AES_GCM"); + addMech(CKM_AES_CCM, "CKM_AES_CCM"); + addMech(CKM_AES_CTS, "CKM_AES_CTS"); + addMech(CKM_AES_CMAC, "CKM_AES_CMAC"); + addMech(CKM_AES_CMAC_GENERAL, "CKM_AES_CMAC_GENERAL"); + addMech(CKM_AES_XCBC_MAC, "CKM_AES_XCBC_MAC"); + addMech(CKM_AES_XCBC_MAC_96, "CKM_AES_XCBC_MAC_96"); + addMech(CKM_AES_GMAC, "CKM_AES_GMAC"); + + addMech(CKM_BLOWFISH_KEY_GEN, "CKM_BLOWFISH_KEY_GEN"); + addMech(CKM_BLOWFISH_CBC, "CKM_BLOWFISH_CBC"); + addMech(CKM_TWOFISH_KEY_GEN, "CKM_TWOFISH_KEY_GEN"); + addMech(CKM_TWOFISH_CBC, "CKM_TWOFISH_CBC"); + addMech(CKM_BLOWFISH_CBC_PAD, "CKM_BLOWFISH_CBC_PAD"); + addMech(CKM_TWOFISH_CBC_PAD, "CKM_TWOFISH_CBC_PAD"); + + addMech(CKM_DES_ECB_ENCRYPT_DATA, "CKM_DES_ECB_ENCRYPT_DATA"); + addMech(CKM_DES_CBC_ENCRYPT_DATA, "CKM_DES_CBC_ENCRYPT_DATA"); + addMech(CKM_DES3_ECB_ENCRYPT_DATA, "CKM_DES3_ECB_ENCRYPT_DATA"); + addMech(CKM_DES3_CBC_ENCRYPT_DATA, "CKM_DES3_CBC_ENCRYPT_DATA"); + addMech(CKM_AES_ECB_ENCRYPT_DATA, "CKM_AES_ECB_ENCRYPT_DATA"); + addMech(CKM_AES_CBC_ENCRYPT_DATA, "CKM_AES_CBC_ENCRYPT_DATA"); + + addMech(CKM_GOSTR3410_KEY_PAIR_GEN, "CKM_GOSTR3410_KEY_PAIR_GEN"); + addMech(CKM_GOSTR3410, "CKM_GOSTR3410"); + addMech(CKM_GOSTR3410_WITH_GOSTR3411, "CKM_GOSTR3410_WITH_GOSTR3411"); + addMech(CKM_GOSTR3410_KEY_WRAP, "CKM_GOSTR3410_KEY_WRAP"); + addMech(CKM_GOSTR3410_DERIVE, "CKM_GOSTR3410_DERIVE"); + addMech(CKM_GOSTR3411, "CKM_GOSTR3411"); + addMech(CKM_GOSTR3411_HMAC, "CKM_GOSTR3411_HMAC"); + addMech(CKM_GOST28147_KEY_GEN, "CKM_GOST28147_KEY_GEN"); + addMech(CKM_GOST28147_ECB, "CKM_GOST28147_ECB"); + addMech(CKM_GOST28147, "CKM_GOST28147"); + addMech(CKM_GOST28147_MAC, "CKM_GOST28147_MAC"); + addMech(CKM_GOST28147_KEY_WRAP, "CKM_GOST28147_KEY_WRAP"); + addMech(CKM_CHACHA20_KEY_GEN, "CKM_CHACHA20_KEY_GEN"); + addMech(CKM_CHACHA20, "CKM_CHACHA20"); + addMech(CKM_POLY1305_KEY_GEN, "CKM_POLY1305_KEY_GEN"); + addMech(CKM_POLY1305, "CKM_POLY1305"); + + addMech(CKM_DSA_PARAMETER_GEN, "CKM_DSA_PARAMETER_GEN"); + addMech(CKM_DH_PKCS_PARAMETER_GEN, "CKM_DH_PKCS_PARAMETER_GEN"); + addMech(CKM_X9_42_DH_PARAMETER_GEN, "CKM_X9_42_DH_PARAMETER_GEN"); + addMech(CKM_DSA_PROBABLISTIC_PARAMETER_GEN, + "CKM_DSA_PROBABLISTIC_PARAMETER_GEN"); + addMech(CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN, + "CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN"); + addMech(CKM_DSA_FIPS_G_GEN, "CKM_DSA_FIPS_G_GEN"); + + addMech(CKM_AES_OFB, "CKM_AES_OFB"); + addMech(CKM_AES_CFB64, "CKM_AES_CFB64"); + addMech(CKM_AES_CFB8, "CKM_AES_CFB8"); + addMech(CKM_AES_CFB128, "CKM_AES_CFB128"); + addMech(CKM_AES_CFB1, "CKM_AES_CFB1"); + addMech(CKM_AES_KEY_WRAP, "CKM_AES_KEY_WRAP"); + addMech(CKM_AES_KEY_WRAP_PAD, "CKM_AES_KEY_WRAP_PAD"); + addMech(CKM_AES_KEY_WRAP_KWP, "CKM_AES_KEY_WRAP_KWP"); + addMech(CKM_RSA_PKCS_TPM_1_1, "CKM_RSA_PKCS_TPM_1_1"); + addMech(CKM_RSA_PKCS_OAEP_TPM_1_1, "CKM_RSA_PKCS_OAEP_TPM_1_1"); + addMech(CKM_SHA_1_KEY_GEN, "CKM_SHA_1_KEY_GEN"); + addMech(CKM_SHA224_KEY_GEN, "CKM_SHA224_KEY_GEN"); + addMech(CKM_SHA256_KEY_GEN, "CKM_SHA256_KEY_GEN"); + addMech(CKM_SHA384_KEY_GEN, "CKM_SHA384_KEY_GEN"); + addMech(CKM_SHA512_KEY_GEN, "CKM_SHA512_KEY_GEN"); + addMech(CKM_SHA512_224_KEY_GEN, "CKM_SHA512_224_KEY_GEN"); + addMech(CKM_SHA512_256_KEY_GEN, "CKM_SHA512_256_KEY_GEN"); + addMech(CKM_SHA512_T_KEY_GEN, "CKM_SHA512_T_KEY_GEN"); + addMech(CKM_NULL, "CKM_NULL"); + addMech(CKM_BLAKE2B_160, "CKM_BLAKE2B_160"); + addMech(CKM_BLAKE2B_160_HMAC, "CKM_BLAKE2B_160_HMAC"); + addMech(CKM_BLAKE2B_160_HMAC_GENERAL, "CKM_BLAKE2B_160_HMAC_GENERAL"); + addMech(CKM_BLAKE2B_160_KEY_DERIVE, "CKM_BLAKE2B_160_KEY_DERIVE"); + addMech(CKM_BLAKE2B_160_KEY_GEN, "CKM_BLAKE2B_160_KEY_GEN"); + addMech(CKM_BLAKE2B_256, "CKM_BLAKE2B_256"); + addMech(CKM_BLAKE2B_256_HMAC, "CKM_BLAKE2B_256_HMAC"); + addMech(CKM_BLAKE2B_256_HMAC_GENERAL, "CKM_BLAKE2B_256_HMAC_GENERAL"); + addMech(CKM_BLAKE2B_256_KEY_DERIVE, "CKM_BLAKE2B_256_KEY_DERIVE"); + addMech(CKM_BLAKE2B_256_KEY_GEN, "CKM_BLAKE2B_256_KEY_GEN"); + addMech(CKM_BLAKE2B_384, "CKM_BLAKE2B_384"); + addMech(CKM_BLAKE2B_384_HMAC, "CKM_BLAKE2B_384_HMAC"); + addMech(CKM_BLAKE2B_384_HMAC_GENERAL, "CKM_BLAKE2B_384_HMAC_GENERAL"); + addMech(CKM_BLAKE2B_384_KEY_DERIVE, "CKM_BLAKE2B_384_KEY_DERIVE"); + addMech(CKM_BLAKE2B_384_KEY_GEN, "CKM_BLAKE2B_384_KEY_GEN"); + addMech(CKM_BLAKE2B_512, "CKM_BLAKE2B_512"); + addMech(CKM_BLAKE2B_512_HMAC, "CKM_BLAKE2B_512_HMAC"); + addMech(CKM_BLAKE2B_512_HMAC_GENERAL, "CKM_BLAKE2B_512_HMAC_GENERAL"); + addMech(CKM_BLAKE2B_512_KEY_DERIVE, "CKM_BLAKE2B_512_KEY_DERIVE"); + addMech(CKM_BLAKE2B_512_KEY_GEN, "CKM_BLAKE2B_512_KEY_GEN"); + addMech(CKM_SALSA20, "CKM_SALSA20"); + addMech(CKM_CHACHA20_POLY1305, "CKM_CHACHA20_POLY1305"); + addMech(CKM_SALSA20_POLY1305, "CKM_SALSA20_POLY1305"); + addMech(CKM_X3DH_INITIALIZE, "CKM_X3DH_INITIALIZE"); + addMech(CKM_X3DH_RESPOND, "CKM_X3DH_RESPOND"); + addMech(CKM_X2RATCHET_INITIALIZE, "CKM_X2RATCHET_INITIALIZE"); + addMech(CKM_X2RATCHET_RESPOND, "CKM_X2RATCHET_RESPOND"); + addMech(CKM_X2RATCHET_ENCRYPT, "CKM_X2RATCHET_ENCRYPT"); + addMech(CKM_X2RATCHET_DECRYPT, "CKM_X2RATCHET_DECRYPT"); + addMech(CKM_XEDDSA, "CKM_XEDDSA"); + addMech(CKM_HKDF_DERIVE, "CKM_HKDF_DERIVE"); + addMech(CKM_HKDF_DATA, "CKM_HKDF_DATA"); + addMech(CKM_HKDF_KEY_GEN, "CKM_HKDF_KEY_GEN"); + addMech(CKM_SALSA20_KEY_GEN, "CKM_SALSA20_KEY_GEN"); + addMech(CKM_SP800_108_COUNTER_KDF, "CKM_SP800_108_COUNTER_KDF"); + addMech(CKM_SP800_108_FEEDBACK_KDF, "CKM_SP800_108_FEEDBACK_KDF"); + addMech(CKM_SP800_108_DOUBLE_PIPELINE_KDF, + "CKM_SP800_108_DOUBLE_PIPELINE_KDF"); + + addMech(CKM_VENDOR_DEFINED, "CKM_VENDOR_DEFINED"); + + addMech(CKM_NSS_TLS_PRF_GENERAL, "CKM_NSS_TLS_PRF_GENERAL"); + + addMech(PCKM_SECURERANDOM, "SecureRandom"); + addMech(PCKM_KEYSTORE, "KeyStore"); + + addHashMech(CKM_SHA_1, "SHA-1", "SHA", "SHA1"); + addHashMech(CKM_SHA224, "SHA-224", "SHA224"); + addHashMech(CKM_SHA256, "SHA-256", "SHA256"); + addHashMech(CKM_SHA384, "SHA-384", "SHA384"); + addHashMech(CKM_SHA512, "SHA-512", "SHA512"); + addHashMech(CKM_SHA512_224, "SHA-512/224", "SHA512/224"); + addHashMech(CKM_SHA512_256, "SHA-512/256", "SHA512/256"); + addHashMech(CKM_SHA3_224, "SHA3-224"); + addHashMech(CKM_SHA3_256, "SHA3-256"); + addHashMech(CKM_SHA3_384, "SHA3-384"); + addHashMech(CKM_SHA3_512, "SHA3-512"); + + addKeyType(CKK_RSA, "CKK_RSA"); + addKeyType(CKK_DSA, "CKK_DSA"); + addKeyType(CKK_DH, "CKK_DH"); + addKeyType(CKK_EC, "CKK_EC"); + addKeyType(CKK_X9_42_DH, "CKK_X9_42_DH"); + addKeyType(CKK_KEA, "CKK_KEA"); + addKeyType(CKK_GENERIC_SECRET, "CKK_GENERIC_SECRET"); + addKeyType(CKK_RC2, "CKK_RC2"); + addKeyType(CKK_RC4, "CKK_RC4"); + addKeyType(CKK_DES, "CKK_DES"); + addKeyType(CKK_DES2, "CKK_DES2"); + addKeyType(CKK_DES3, "CKK_DES3"); + addKeyType(CKK_CAST, "CKK_CAST"); + addKeyType(CKK_CAST3, "CKK_CAST3"); + addKeyType(CKK_CAST128, "CKK_CAST128"); + addKeyType(CKK_RC5, "CKK_RC5"); + addKeyType(CKK_IDEA, "CKK_IDEA"); + addKeyType(CKK_SKIPJACK, "CKK_SKIPJACK"); + addKeyType(CKK_BATON, "CKK_BATON"); + addKeyType(CKK_JUNIPER, "CKK_JUNIPER"); + addKeyType(CKK_CDMF, "CKK_CDMF"); + addKeyType(CKK_AES, "CKK_AES"); + addKeyType(CKK_BLOWFISH, "CKK_BLOWFISH"); + addKeyType(CKK_TWOFISH, "CKK_TWOFISH"); + addKeyType(CKK_SECURID, "CKK_SECURID"); + addKeyType(CKK_HOTP, "CKK_HOTP"); + addKeyType(CKK_ACTI, "CKK_ACTI"); + addKeyType(CKK_CAMELLIA, "CKK_CAMELLIA"); + addKeyType(CKK_ARIA, "CKK_ARIA"); + addKeyType(CKK_MD5_HMAC, "CKK_MD5_HMAC"); + addKeyType(CKK_SHA_1_HMAC, "CKK_SHA_1_HMAC"); + addKeyType(CKK_RIPEMD128_HMAC, "CKK_RIPEMD128_HMAC"); + addKeyType(CKK_RIPEMD160_HMAC, "CKK_RIPEMD160_HMAC"); + addKeyType(CKK_SHA256_HMAC, "CKK_SHA256_HMAC"); + addKeyType(CKK_SHA384_HMAC, "CKK_SHA384_HMAC"); + addKeyType(CKK_SHA512_HMAC, "CKK_SHA512_HMAC"); + addKeyType(CKK_SHA224_HMAC, "CKK_SHA224_HMAC"); + addKeyType(CKK_SEED, "CKK_SEED"); + addKeyType(CKK_GOSTR3410, "CKK_GOSTR3410"); + addKeyType(CKK_GOSTR3411, "CKK_GOSTR3411"); + addKeyType(CKK_GOST28147, "CKK_GOST28147"); + addKeyType(CKK_CHACHA20, "CKK_CHACHA20"); + addKeyType(CKK_POLY1305, "CKK_POLY1305"); + addKeyType(CKK_AES_XTS, "CKK_AES_XTS"); + + addKeyType(CKK_SHA3_224_HMAC, "CKK_SHA3_224_HMAC"); + addKeyType(CKK_SHA3_256_HMAC, "CKK_SHA3_256_HMAC"); + addKeyType(CKK_SHA3_384_HMAC, "CKK_SHA3_384_HMAC"); + addKeyType(CKK_SHA3_512_HMAC, "CKK_SHA3_512_HMAC"); + addKeyType(CKK_BLAKE2B_160_HMAC, "CKK_BLAKE2B_160_HMAC"); + addKeyType(CKK_BLAKE2B_256_HMAC, "CKK_BLAKE2B_256_HMAC"); + addKeyType(CKK_BLAKE2B_384_HMAC, "CKK_BLAKE2B_384_HMAC"); + addKeyType(CKK_BLAKE2B_512_HMAC, "CKK_BLAKE2B_512_HMAC"); + addKeyType(CKK_SALSA20, "CKK_SALSA20"); + addKeyType(CKK_X2RATCHET, "CKK_X2RATCHET"); + addKeyType(CKK_EC_EDWARDS, "CKK_EC_EDWARDS"); + addKeyType(CKK_EC_MONTGOMERY, "CKK_EC_MONTGOMERY"); + addKeyType(CKK_HKDF, "CKK_HKDF"); + + addKeyType(CKK_SHA512_224_HMAC, "CKK_SHA512_224_HMAC"); + addKeyType(CKK_SHA512_256_HMAC, "CKK_SHA512_256_HMAC"); + addKeyType(CKK_SHA512_T_HMAC, "CKK_SHA512_T_HMAC"); + + addKeyType(CKK_VENDOR_DEFINED, "CKK_VENDOR_DEFINED"); + + addKeyType(PCKK_ANY, "*"); + + addAttribute(CKA_CLASS, "CKA_CLASS"); + addAttribute(CKA_TOKEN, "CKA_TOKEN"); + addAttribute(CKA_PRIVATE, "CKA_PRIVATE"); + addAttribute(CKA_LABEL, "CKA_LABEL"); + addAttribute(CKA_UNIQUE_ID, "CKA_UNIQUE_ID"); + addAttribute(CKA_APPLICATION, "CKA_APPLICATION"); + addAttribute(CKA_VALUE, "CKA_VALUE"); + addAttribute(CKA_OBJECT_ID, "CKA_OBJECT_ID"); + addAttribute(CKA_CERTIFICATE_TYPE, "CKA_CERTIFICATE_TYPE"); + addAttribute(CKA_ISSUER, "CKA_ISSUER"); + addAttribute(CKA_SERIAL_NUMBER, "CKA_SERIAL_NUMBER"); + addAttribute(CKA_AC_ISSUER, "CKA_AC_ISSUER"); + addAttribute(CKA_OWNER, "CKA_OWNER"); + addAttribute(CKA_ATTR_TYPES, "CKA_ATTR_TYPES"); + addAttribute(CKA_TRUSTED, "CKA_TRUSTED"); + addAttribute(CKA_CERTIFICATE_CATEGORY, "CKA_CERTIFICATE_CATEGORY"); + addAttribute(CKA_JAVA_MIDP_SECURITY_DOMAIN, + "CKA_JAVA_MIDP_SECURITY_DOMAIN"); + addAttribute(CKA_URL, "CKA_URL"); + addAttribute(CKA_HASH_OF_SUBJECT_PUBLIC_KEY, + "CKA_HASH_OF_SUBJECT_PUBLIC_KEY"); + addAttribute(CKA_HASH_OF_ISSUER_PUBLIC_KEY, + "CKA_HASH_OF_ISSUER_PUBLIC_KEY"); + addAttribute(CKA_NAME_HASH_ALGORITHM, "CKA_NAME_HASH_ALGORITHM"); + addAttribute(CKA_CHECK_VALUE, "CKA_CHECK_VALUE"); + addAttribute(CKA_KEY_TYPE, "CKA_KEY_TYPE"); + addAttribute(CKA_SUBJECT, "CKA_SUBJECT"); + addAttribute(CKA_ID, "CKA_ID"); + addAttribute(CKA_SENSITIVE, "CKA_SENSITIVE"); + addAttribute(CKA_ENCRYPT, "CKA_ENCRYPT"); + addAttribute(CKA_DECRYPT, "CKA_DECRYPT"); + addAttribute(CKA_WRAP, "CKA_WRAP"); + addAttribute(CKA_UNWRAP, "CKA_UNWRAP"); + addAttribute(CKA_SIGN, "CKA_SIGN"); + addAttribute(CKA_SIGN_RECOVER, "CKA_SIGN_RECOVER"); + addAttribute(CKA_VERIFY, "CKA_VERIFY"); + addAttribute(CKA_VERIFY_RECOVER, "CKA_VERIFY_RECOVER"); + addAttribute(CKA_DERIVE, "CKA_DERIVE"); + addAttribute(CKA_START_DATE, "CKA_START_DATE"); + addAttribute(CKA_END_DATE, "CKA_END_DATE"); + addAttribute(CKA_MODULUS, "CKA_MODULUS"); + addAttribute(CKA_MODULUS_BITS, "CKA_MODULUS_BITS"); + addAttribute(CKA_PUBLIC_EXPONENT, "CKA_PUBLIC_EXPONENT"); + addAttribute(CKA_PRIVATE_EXPONENT, "CKA_PRIVATE_EXPONENT"); + addAttribute(CKA_PRIME_1, "CKA_PRIME_1"); + addAttribute(CKA_PRIME_2, "CKA_PRIME_2"); + addAttribute(CKA_EXPONENT_1, "CKA_EXPONENT_1"); + addAttribute(CKA_EXPONENT_2, "CKA_EXPONENT_2"); + addAttribute(CKA_COEFFICIENT, "CKA_COEFFICIENT"); + addAttribute(CKA_PUBLIC_KEY_INFO, "CKA_PUBLIC_KEY_INFO"); + addAttribute(CKA_PRIME, "CKA_PRIME"); + addAttribute(CKA_SUBPRIME, "CKA_SUBPRIME"); + addAttribute(CKA_BASE, "CKA_BASE"); + addAttribute(CKA_PRIME_BITS, "CKA_PRIME_BITS"); + addAttribute(CKA_SUB_PRIME_BITS, "CKA_SUB_PRIME_BITS"); + addAttribute(CKA_VALUE_BITS, "CKA_VALUE_BITS"); + addAttribute(CKA_VALUE_LEN, "CKA_VALUE_LEN"); + + addAttribute(CKA_EXTRACTABLE, "CKA_EXTRACTABLE"); + addAttribute(CKA_LOCAL, "CKA_LOCAL"); + addAttribute(CKA_NEVER_EXTRACTABLE, "CKA_NEVER_EXTRACTABLE"); + addAttribute(CKA_ALWAYS_SENSITIVE, "CKA_ALWAYS_SENSITIVE"); + + addAttribute(CKA_KEY_GEN_MECHANISM, "CKA_KEY_GEN_MECHANISM"); + addAttribute(CKA_MODIFIABLE, "CKA_MODIFIABLE"); + addAttribute(CKA_COPYABLE, "CKA_COPYABLE"); + addAttribute(CKA_DESTROYABLE, "CKA_DESTROYABLE"); + + addAttribute(CKA_EC_PARAMS, "CKA_EC_PARAMS"); + addAttribute(CKA_EC_POINT, "CKA_EC_POINT"); + + addAttribute(CKA_SECONDARY_AUTH, "CKA_SECONDARY_AUTH"); + addAttribute(CKA_AUTH_PIN_FLAGS, "CKA_AUTH_PIN_FLAGS"); + addAttribute(CKA_ALWAYS_AUTHENTICATE, "CKA_ALWAYS_AUTHENTICATE"); + addAttribute(CKA_WRAP_WITH_TRUSTED, "CKA_WRAP_WITH_TRUSTED"); + addAttribute(CKA_WRAP_TEMPLATE, "CKA_WRAP_TEMPLATE"); + addAttribute(CKA_UNWRAP_TEMPLATE, "CKA_UNWRAP_TEMPLATE"); + addAttribute(CKA_DERIVE_TEMPLATE, "CKA_DERIVE_TEMPLATE"); + addAttribute(CKA_OTP_FORMAT, "CKA_OTP_FORMAT"); + addAttribute(CKA_OTP_LENGTH, "CKA_OTP_LENGTH"); + addAttribute(CKA_OTP_TIME_INTERVAL, "CKA_OTP_TIME_INTERVAL"); + addAttribute(CKA_OTP_USER_FRIENDLY_MODE,"CKA_OTP_USER_FRIENDLY_MODE"); + addAttribute(CKA_OTP_CHALLENGE_REQUIREMENT, + "CKA_OTP_CHALLENGE_REQUIREMENT"); + addAttribute(CKA_OTP_TIME_REQUIREMENT, "CKA_OTP_TIME_REQUIREMENT"); + addAttribute(CKA_OTP_COUNTER_REQUIREMENT, + "CKA_OTP_COUNTER_REQUIREMENT"); + addAttribute(CKA_OTP_PIN_REQUIREMENT, "CKA_OTP_PIN_REQUIREMENT"); + addAttribute(CKA_OTP_COUNTER, "CKA_OTP_COUNTER"); + addAttribute(CKA_OTP_TIME, "CKA_OTP_TIME"); + addAttribute(CKA_OTP_USER_IDENTIFIER, "CKA_OTP_USER_IDENTIFIER"); + addAttribute(CKA_OTP_SERVICE_IDENTIFIER,"CKA_OTP_SERVICE_IDENTIFIER"); + addAttribute(CKA_OTP_SERVICE_LOGO, "CKA_OTP_SERVICE_LOGO"); + addAttribute(CKA_OTP_SERVICE_LOGO_TYPE, "CKA_OTP_SERVICE_LOGO_TYPE"); + addAttribute(CKA_GOSTR3410_PARAMS, "CKA_GOSTR3410_PARAMS"); + addAttribute(CKA_GOSTR3411_PARAMS, "CKA_GOSTR3411_PARAMS"); + addAttribute(CKA_GOST28147_PARAMS, "CKA_GOST28147_PARAMS"); + + addAttribute(CKA_HW_FEATURE_TYPE, "CKA_HW_FEATURE_TYPE"); + addAttribute(CKA_RESET_ON_INIT, "CKA_RESET_ON_INIT"); + addAttribute(CKA_HAS_RESET, "CKA_HAS_RESET"); + + addAttribute(CKA_PIXEL_X, "CKA_PIXEL_X"); + addAttribute(CKA_PIXEL_Y, "CKA_PIXEL_Y"); + addAttribute(CKA_RESOLUTION, "CKA_RESOLUTION"); + addAttribute(CKA_CHAR_ROWS, "CKA_CHAR_ROWS"); + addAttribute(CKA_CHAR_COLUMNS, "CKA_CHAR_COLUMNS"); + addAttribute(CKA_COLOR, "CKA_COLOR"); + addAttribute(CKA_BITS_PER_PIXEL, "CKA_BITS_PER_PIXEL"); + addAttribute(CKA_CHAR_SETS, "CKA_CHAR_SETS"); + addAttribute(CKA_ENCODING_METHODS, "CKA_ENCODING_METHODS"); + addAttribute(CKA_MIME_TYPES, "CKA_MIME_TYPES"); + addAttribute(CKA_MECHANISM_TYPE, "CKA_MECHANISM_TYPE"); + addAttribute(CKA_REQUIRED_CMS_ATTRIBUTES, + "CKA_REQUIRED_CMS_ATTRIBUTES"); + addAttribute(CKA_DEFAULT_CMS_ATTRIBUTES,"CKA_DEFAULT_CMS_ATTRIBUTES"); + addAttribute(CKA_SUPPORTED_CMS_ATTRIBUTES, + "CKA_SUPPORTED_CMS_ATTRIBUTES"); + addAttribute(CKA_ALLOWED_MECHANISMS, "CKA_ALLOWED_MECHANISMS"); + addAttribute(CKA_PROFILE_ID, "CKA_PROFILE_ID"); + addAttribute(CKA_X2RATCHET_BAG, "CKA_X2RATCHET_BAG"); + addAttribute(CKA_X2RATCHET_BAGSIZE, "CKA_X2RATCHET_BAGSIZE"); + addAttribute(CKA_X2RATCHET_BOBS1STMSG, "CKA_X2RATCHET_BOBS1STMSG"); + addAttribute(CKA_X2RATCHET_CKR, "CKA_X2RATCHET_CKR"); + addAttribute(CKA_X2RATCHET_CKS, "CKA_X2RATCHET_CKS"); + addAttribute(CKA_X2RATCHET_DHP, "CKA_X2RATCHET_DHP"); + addAttribute(CKA_X2RATCHET_DHR, "CKA_X2RATCHET_DHR"); + addAttribute(CKA_X2RATCHET_DHS, "CKA_X2RATCHET_DHS"); + addAttribute(CKA_X2RATCHET_HKR, "CKA_X2RATCHET_HKR"); + addAttribute(CKA_X2RATCHET_HKS, "CKA_X2RATCHET_HKS"); + addAttribute(CKA_X2RATCHET_ISALICE, "CKA_X2RATCHET_ISALICE"); + addAttribute(CKA_X2RATCHET_NHKR, "CKA_X2RATCHET_NHKR"); + addAttribute(CKA_X2RATCHET_NHKS, "CKA_X2RATCHET_NHKS"); + addAttribute(CKA_X2RATCHET_NR, "CKA_X2RATCHET_NR"); + addAttribute(CKA_X2RATCHET_NS, "CKA_X2RATCHET_NS"); + addAttribute(CKA_X2RATCHET_PNS, "CKA_X2RATCHET_PNS"); + addAttribute(CKA_X2RATCHET_RK, "CKA_X2RATCHET_RK"); + + addAttribute(CKA_VENDOR_DEFINED, "CKA_VENDOR_DEFINED"); + addAttribute(CKA_NETSCAPE_DB, "CKA_NETSCAPE_DB"); + + addAttribute(CKA_NETSCAPE_TRUST_SERVER_AUTH, "CKA_NETSCAPE_TRUST_SERVER_AUTH"); + addAttribute(CKA_NETSCAPE_TRUST_CLIENT_AUTH, "CKA_NETSCAPE_TRUST_CLIENT_AUTH"); + addAttribute(CKA_NETSCAPE_TRUST_CODE_SIGNING, "CKA_NETSCAPE_TRUST_CODE_SIGNING"); + addAttribute(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION, "CKA_NETSCAPE_TRUST_EMAIL_PROTECTION"); + addAttribute(CKA_NETSCAPE_CERT_SHA1_HASH, "CKA_NETSCAPE_CERT_SHA1_HASH"); + addAttribute(CKA_NETSCAPE_CERT_MD5_HASH, "CKA_NETSCAPE_CERT_MD5_HASH"); + + addObjectClass(CKO_DATA, "CKO_DATA"); + addObjectClass(CKO_CERTIFICATE, "CKO_CERTIFICATE"); + addObjectClass(CKO_PUBLIC_KEY, "CKO_PUBLIC_KEY"); + addObjectClass(CKO_PRIVATE_KEY, "CKO_PRIVATE_KEY"); + addObjectClass(CKO_SECRET_KEY, "CKO_SECRET_KEY"); + addObjectClass(CKO_HW_FEATURE, "CKO_HW_FEATURE"); + addObjectClass(CKO_DOMAIN_PARAMETERS, "CKO_DOMAIN_PARAMETERS"); + addObjectClass(CKO_MECHANISM, "CKO_MECHANISM"); + addObjectClass(CKO_OTP_KEY, "CKO_OTP_KEY"); + addObjectClass(CKO_PROFILE, "CKO_PROFILE"); + addObjectClass(CKO_VENDOR_DEFINED, "CKO_VENDOR_DEFINED"); + + addObjectClass(PCKO_ANY, "*"); + + addMGF(CKG_MGF1_SHA1, "CKG_MGF1_SHA1"); + addMGF(CKG_MGF1_SHA256, "CKG_MGF1_SHA256"); + addMGF(CKG_MGF1_SHA384, "CKG_MGF1_SHA384"); + addMGF(CKG_MGF1_SHA512, "CKG_MGF1_SHA512"); + addMGF(CKG_MGF1_SHA224, "CKG_MGF1_SHA224"); + addMGF(CKG_MGF1_SHA3_224, "CKG_MGF1_SHA3_224"); + addMGF(CKG_MGF1_SHA3_256, "CKG_MGF1_SHA3_256"); + addMGF(CKG_MGF1_SHA3_384, "CKG_MGF1_SHA3_384"); + addMGF(CKG_MGF1_SHA3_512, "CKG_MGF1_SHA3_512"); + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11.java new file mode 100644 index 0000000..e49fc45 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11.java @@ -0,0 +1,1908 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * This is the default implementation of the PKCS11 interface. IT connects to + * the pkcs11wrapper.dll file, which is the native part of this library. + * The strange and awkward looking initialization was chosen to avoid calling + * loadLibrary from a static initialization block, because this would complicate + * the use in applets. + * + * @author Karl Scheibelhofer + * @author Martin Schlaeffer + * @invariants (pkcs11ModulePath_ <> null) + */ +public class PKCS11 { + + /** + * The name of the native part of the wrapper; i.e. the filename without + * the extension (e.g. ".DLL" or ".so"). + */ + private static final String PKCS11_WRAPPER = "j2pkcs11"; + + static { + // cannot use LoadLibraryAction because that would make the native + // library available to the bootclassloader, but we run in the + // extension classloader. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + System.loadLibrary(PKCS11_WRAPPER); + return null; + } + }); + initializeLibrary(); + } + + public static void loadNative() { + // dummy method that can be called to make sure the native + // portion has been loaded. actual loading happens in the + // static initializer, hence this method is empty. + } + + /* ***************************************************************************** + * Utility, Resource Clean up + ******************************************************************************/ + // always return 0L + public static native long freeMechanism(long hMechanism); + + /** + * The PKCS#11 module to connect to. This is the PKCS#11 driver of the token; + * e.g. pk2priv.dll. + */ + private final String pkcs11ModulePath; + + private long pNativeData; + + /** + * This method does the initialization of the native library. It is called + * exactly once for this class. + * + * @preconditions + * @postconditions + */ + private static native void initializeLibrary(); + + // XXX + /** + * This method does the finalization of the native library. It is called + * exactly once for this class. The library uses this method for a clean-up + * of any resources. + * + * @preconditions + * @postconditions + */ + private static native void finalizeLibrary(); + + private static final Map moduleMap = + new HashMap(); + + /** + * Connects to the PKCS#11 driver given. The filename must contain the + * path, if the driver is not in the system's search path. + * + * @param pkcs11ModulePath the PKCS#11 library path + * @preconditions (pkcs11ModulePath <> null) + * @postconditions + */ + PKCS11(String pkcs11ModulePath, String functionListName) + throws IOException { + connect(pkcs11ModulePath, functionListName); + this.pkcs11ModulePath = pkcs11ModulePath; + } + + public static synchronized PKCS11 getInstance(String pkcs11ModulePath, + String functionList, CK_C_INITIALIZE_ARGS pInitArgs, + boolean omitInitialize) throws IOException, PKCS11Exception { + // we may only call C_Initialize once per native .so/.dll + // so keep a cache using the (non-canonicalized!) path + PKCS11 pkcs11 = moduleMap.get(pkcs11ModulePath); + if (pkcs11 == null) { + if ((pInitArgs != null) + && ((pInitArgs.flags & CKF_OS_LOCKING_OK) != 0)) { + pkcs11 = new PKCS11(pkcs11ModulePath, functionList); + } else { + pkcs11 = new SynchronizedPKCS11(pkcs11ModulePath, functionList); + } + if (omitInitialize == false) { + try { + pkcs11.C_Initialize(pInitArgs); + } catch (PKCS11Exception e) { + // ignore already-initialized error code + // rethrow all other errors + if (e.getErrorCode() != CKR_CRYPTOKI_ALREADY_INITIALIZED) { + throw e; + } + } + } + moduleMap.put(pkcs11ModulePath, pkcs11); + } + return pkcs11; + } + + /** + * Connects this object to the specified PKCS#11 library. This method is for + * internal use only. + * Declared private, because incorrect handling may result in errors in the + * native part. + * + * @param pkcs11ModulePath The PKCS#11 library path. + * @preconditions (pkcs11ModulePath <> null) + * @postconditions + */ + private native void connect(String pkcs11ModulePath, String functionListName) + throws IOException; + + /** + * Disconnects the PKCS#11 library from this object. After calling this + * method, this object is no longer connected to a native PKCS#11 module + * and any subsequent calls to C_ methods will fail. This method is for + * internal use only. + * Declared private, because incorrect handling may result in errors in the + * native part. + * + * @preconditions + * @postconditions + */ + private native void disconnect(); + + + // Implementation of PKCS11 methods delegated to native pkcs11wrapper library + +/* ***************************************************************************** + * General-purpose + ******************************************************************************/ + + /** + * C_Initialize initializes the Cryptoki library. + * (General-purpose) + * + * @param pInitArgs if pInitArgs is not NULL it gets casted to + * CK_C_INITIALIZE_ARGS_PTR and dereferenced + * (PKCS#11 param: CK_VOID_PTR pInitArgs) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + native void C_Initialize(Object pInitArgs) throws PKCS11Exception; + + /** + * C_Finalize indicates that an application is done with the + * Cryptoki library + * (General-purpose) + * + * @param pReserved is reserved. Should be NULL_PTR + * (PKCS#11 param: CK_VOID_PTR pReserved) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pReserved == null) + * @postconditions + */ + public native void C_Finalize(Object pReserved) throws PKCS11Exception; + + + /** + * C_GetInfo returns general information about Cryptoki. + * (General-purpose) + * + * @return the information. + * (PKCS#11 param: CK_INFO_PTR pInfo) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native CK_INFO C_GetInfo() throws PKCS11Exception; + + +/* ***************************************************************************** + * Slot and token management + ******************************************************************************/ + + /** + * C_GetSlotList obtains a list of slots in the system. + * (Slot and token management) + * + * @param tokenPresent if true only Slot IDs with a token are returned + * (PKCS#11 param: CK_BBOOL tokenPresent) + * @return a long array of slot IDs and number of Slot IDs + * (PKCS#11 param: CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native long[] C_GetSlotList(boolean tokenPresent) + throws PKCS11Exception; + + + /** + * C_GetSlotInfo obtains information about a particular slot in + * the system. + * (Slot and token management) + * + * @param slotID the ID of the slot + * (PKCS#11 param: CK_SLOT_ID slotID) + * @return the slot information + * (PKCS#11 param: CK_SLOT_INFO_PTR pInfo) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native CK_SLOT_INFO C_GetSlotInfo(long slotID) throws PKCS11Exception; + + + /** + * C_GetTokenInfo obtains information about a particular token + * in the system. + * (Slot and token management) + * + * @param slotID ID of the token's slot + * (PKCS#11 param: CK_SLOT_ID slotID) + * @return the token information + * (PKCS#11 param: CK_TOKEN_INFO_PTR pInfo) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native CK_TOKEN_INFO C_GetTokenInfo(long slotID) + throws PKCS11Exception; + + + /** + * C_GetMechanismList obtains a list of mechanism types + * supported by a token. + * (Slot and token management) + * + * @param slotID ID of the token's slot + * (PKCS#11 param: CK_SLOT_ID slotID) + * @return a long array of mechanism types and number of mechanism types + * (PKCS#11 param: CK_MECHANISM_TYPE_PTR pMechanismList, + * CK_ULONG_PTR pulCount) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native long[] C_GetMechanismList(long slotID) throws PKCS11Exception; + + + /** + * C_GetMechanismInfo obtains information about a particular + * mechanism possibly supported by a token. + * (Slot and token management) + * + * @param slotID ID of the token's slot + * (PKCS#11 param: CK_SLOT_ID slotID) + * @param type type of mechanism + * (PKCS#11 param: CK_MECHANISM_TYPE type) + * @return the mechanism info + * (PKCS#11 param: CK_MECHANISM_INFO_PTR pInfo) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native CK_MECHANISM_INFO C_GetMechanismInfo(long slotID, long type) + throws PKCS11Exception; + + + /** + * C_InitToken initializes a token. + * (Slot and token management) + * + * @param slotID ID of the token's slot + * (PKCS#11 param: CK_SLOT_ID slotID) + * @param pPin the SO's initial PIN and the length in bytes of the PIN + * (PKCS#11 param: CK_CHAR_PTR pPin, CK_ULONG ulPinLen) + * @param pLabel 32-byte token label (blank padded) + * (PKCS#11 param: CK_UTF8CHAR_PTR pLabel) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native void C_InitToken(long slotID, char[] pPin, char[] pLabel) +// throws PKCS11Exception; + + + /** + * C_InitPIN initializes the normal user's PIN. + * (Slot and token management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pPin the normal user's PIN and the length in bytes of the PIN + * (PKCS#11 param: CK_CHAR_PTR pPin, CK_ULONG ulPinLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native void C_InitPIN(long hSession, char[] pPin) +// throws PKCS11Exception; + + + /** + * C_SetPIN modifies the PIN of the user who is logged in. + * (Slot and token management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pOldPin the old PIN and the length of the old PIN + * (PKCS#11 param: CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen) + * @param pNewPin the new PIN and the length of the new PIN + * (PKCS#11 param: CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native void C_SetPIN(long hSession, char[] pOldPin, char[] pNewPin) +// throws PKCS11Exception; + + + +/* ***************************************************************************** + * Session management + ******************************************************************************/ + + /** + * C_OpenSession opens a session between an application and a + * token. + * (Session management) + * + * @param slotID the slot's ID + * (PKCS#11 param: CK_SLOT_ID slotID) + * @param flags of CK_SESSION_INFO + * (PKCS#11 param: CK_FLAGS flags) + * @param pApplication passed to callback + * (PKCS#11 param: CK_VOID_PTR pApplication) + * @param Notify the callback function + * (PKCS#11 param: CK_NOTIFY Notify) + * @return the session handle + * (PKCS#11 param: CK_SESSION_HANDLE_PTR phSession) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long C_OpenSession(long slotID, long flags, + Object pApplication, CK_NOTIFY Notify) throws PKCS11Exception; + + + /** + * C_CloseSession closes a session between an application and a + * token. + * (Session management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_CloseSession(long hSession) throws PKCS11Exception; + + + /** + * C_CloseAllSessions closes all sessions with a token. + * (Session management) + * + * @param slotID the ID of the token's slot + * (PKCS#11 param: CK_SLOT_ID slotID) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native void C_CloseAllSessions(long slotID) throws PKCS11Exception; + + + /** + * C_GetSessionInfo obtains information about the session. + * (Session management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @return the session info + * (PKCS#11 param: CK_SESSION_INFO_PTR pInfo) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native CK_SESSION_INFO C_GetSessionInfo(long hSession) + throws PKCS11Exception; + + + /** + * C_GetOperationState obtains the state of the cryptographic operation + * in a session. + * (Session management) + * + * @param hSession session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @return the state and the state length + * (PKCS#11 param: CK_BYTE_PTR pOperationState, + * CK_ULONG_PTR pulOperationStateLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native byte[] C_GetOperationState(long hSession) + throws PKCS11Exception; + + + /** + * C_SetOperationState restores the state of the cryptographic + * operation in a session. + * (Session management) + * + * @param hSession session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pOperationState the state and the state length + * (PKCS#11 param: CK_BYTE_PTR pOperationState, + * CK_ULONG ulOperationStateLen) + * @param hEncryptionKey en/decryption key + * (PKCS#11 param: CK_OBJECT_HANDLE hEncryptionKey) + * @param hAuthenticationKey sign/verify key + * (PKCS#11 param: CK_OBJECT_HANDLE hAuthenticationKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_SetOperationState(long hSession, byte[] pOperationState, + long hEncryptionKey, long hAuthenticationKey) throws PKCS11Exception; + + + /** + * C_Login logs a user into a token. + * (Session management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param userType the user type + * (PKCS#11 param: CK_USER_TYPE userType) + * @param pPin the user's PIN and the length of the PIN + * (PKCS#11 param: CK_CHAR_PTR pPin, CK_ULONG ulPinLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_Login(long hSession, long userType, char[] pPin) + throws PKCS11Exception; + + + /** + * C_Logout logs a user out from a token. + * (Session management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_Logout(long hSession) throws PKCS11Exception; + + + +/* ***************************************************************************** + * Object management + ******************************************************************************/ + + /** + * C_CreateObject creates a new object. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pTemplate the object's template and number of attributes in + * template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @return the object's handle + * (PKCS#11 param: CK_OBJECT_HANDLE_PTR phObject) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long C_CreateObject(long hSession, CK_ATTRIBUTE[] pTemplate) + throws PKCS11Exception; + + + /** + * C_CopyObject copies an object, creating a new object for the + * copy. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param hObject the object's handle + * (PKCS#11 param: CK_OBJECT_HANDLE hObject) + * @param pTemplate the template for the new object and number of attributes + * in template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @return the handle of the copy + * (PKCS#11 param: CK_OBJECT_HANDLE_PTR phNewObject) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long C_CopyObject(long hSession, long hObject, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception; + + + /** + * C_DestroyObject destroys an object. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param hObject the object's handle + * (PKCS#11 param: CK_OBJECT_HANDLE hObject) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_DestroyObject(long hSession, long hObject) + throws PKCS11Exception; + + + /** + * C_GetObjectSize gets the size of an object in bytes. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param hObject the object's handle + * (PKCS#11 param: CK_OBJECT_HANDLE hObject) + * @return the size of the object + * (PKCS#11 param: CK_ULONG_PTR pulSize) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native long C_GetObjectSize(long hSession, long hObject) +// throws PKCS11Exception; + + + /** + * C_GetAttributeValue obtains the value of one or more object + * attributes. The template attributes also receive the values. + * (Object management) + * note: in PKCS#11 pTemplate and the result template are the same + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param hObject the object's handle + * (PKCS#11 param: CK_OBJECT_HANDLE hObject) + * @param pTemplate specifies the attributes and number of attributes to get + * The template attributes also receive the values. + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pTemplate <> null) + * @postconditions (result <> null) + */ + public native void C_GetAttributeValue(long hSession, long hObject, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception; + + + /** + * C_SetAttributeValue modifies the value of one or more object + * attributes + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param hObject the object's handle + * (PKCS#11 param: CK_OBJECT_HANDLE hObject) + * @param pTemplate specifies the attributes and values to get; number of + * attributes in the template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pTemplate <> null) + * @postconditions + */ + public native void C_SetAttributeValue(long hSession, long hObject, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception; + + + /** + * C_FindObjectsInit initializes a search for token and session + * objects that match a template. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pTemplate the object's attribute values to match and the number of + * attributes in search template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_FindObjectsInit(long hSession, CK_ATTRIBUTE[] pTemplate) + throws PKCS11Exception; + + + /** + * C_FindObjects continues a search for token and session + * objects that match a template, obtaining additional object + * handles. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param ulMaxObjectCount the max. object handles to get + * (PKCS#11 param: CK_ULONG ulMaxObjectCount) + * @return the object's handles and the actual number of objects returned + * (PKCS#11 param: CK_ULONG_PTR pulObjectCount) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native long[] C_FindObjects(long hSession, long ulMaxObjectCount) + throws PKCS11Exception; + + + /** + * C_FindObjectsFinal finishes a search for token and session + * objects. + * (Object management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_FindObjectsFinal(long hSession) throws PKCS11Exception; + + + +/* ***************************************************************************** + * Encryption and decryption + ******************************************************************************/ + + /** + * C_EncryptInit initializes an encryption operation. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the encryption mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hKey the handle of the encryption key + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_EncryptInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception; + + + /** + * C_Encrypt encrypts single-part data. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param directIn the address of the to-be-encrypted data + * @param in buffer containing the to-be-encrypted data + * @param inOfs buffer offset of the to-be-encrypted data + * @param inLen length of the to-be-encrypted data + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG ulDataLen) + * @param directOut the address for the encrypted data + * @param out buffer for the encrypted data + * @param outOfs buffer offset for the encrypted data + * @param outLen buffer size for the encrypted data + * @return the length of encrypted data + * (PKCS#11 param: CK_BYTE_PTR pEncryptedData, + * CK_ULONG_PTR pulEncryptedDataLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native int C_Encrypt(long hSession, long directIn, byte[] in, + int inOfs, int inLen, long directOut, byte[] out, int outOfs, + int outLen) throws PKCS11Exception; + + + /** + * C_EncryptUpdate continues a multiple-part encryption + * operation. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param directIn the address of the to-be-encrypted data + * @param in buffer containing the to-be-encrypted data + * @param inOfs buffer offset of the to-be-encrypted data + * @param inLen length of the to-be-encrypted data + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG ulPartLen) + * @param directOut the address for the encrypted data + * @param out buffer for the encrypted data + * @param outOfs buffer offset for the encrypted data + * @param outLen buffer size for the encrypted data + * @return the length of encrypted data for this update + * (PKCS#11 param: CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native int C_EncryptUpdate(long hSession, long directIn, byte[] in, + int inOfs, int inLen, long directOut, byte[] out, int outOfs, + int outLen) throws PKCS11Exception; + + + /** + * C_EncryptFinal finishes a multiple-part encryption + * operation. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param directOut the address for the encrypted data + * @param out buffer for the encrypted data + * @param outOfs buffer offset for the encrypted data + * @param outLen buffer size for the encrypted data + * @return the length of the last part of the encrypted data + * (PKCS#11 param: CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native int C_EncryptFinal(long hSession, long directOut, byte[] out, + int outOfs, int outLen) throws PKCS11Exception; + + + /** + * C_DecryptInit initializes a decryption operation. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the decryption mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hKey the handle of the decryption key + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_DecryptInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception; + + + /** + * C_Decrypt decrypts encrypted data in a single part. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param directIn the address of the to-be-decrypted data + * @param in buffer containing the to-be-decrypted data + * @param inOfs buffer offset of the to-be-decrypted data + * @param inLen length of the to-be-decrypted data + * (PKCS#11 param: CK_BYTE_PTR pDecryptedData, + * CK_ULONG ulDecryptedDataLen) + * @param directOut the address for the decrypted data + * @param out buffer for the decrypted data + * @param outOfs buffer offset for the decrypted data + * @param outLen buffer size for the decrypted data + * @return the length of decrypted data + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native int C_Decrypt(long hSession, long directIn, byte[] in, + int inOfs, int inLen, long directOut, byte[] out, int outOfs, + int outLen) throws PKCS11Exception; + + + /** + * C_DecryptUpdate continues a multiple-part decryption + * operation. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param directIn the address of the to-be-decrypted data + * @param in buffer containing the to-be-decrypted data + * @param inOfs buffer offset of the to-be-decrypted data + * @param inLen length of the to-be-decrypted data + * (PKCS#11 param: CK_BYTE_PTR pDecryptedPart, + * CK_ULONG ulDecryptedPartLen) + * @param directOut the address for the decrypted data + * @param out buffer for the decrypted data + * @param outOfs buffer offset for the decrypted data + * @param outLen buffer size for the decrypted data + * @return the length of decrypted data for this update + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native int C_DecryptUpdate(long hSession, long directIn, byte[] in, + int inOfs, int inLen, long directOut, byte[] out, int outOfs, + int outLen) throws PKCS11Exception; + + + /** + * C_DecryptFinal finishes a multiple-part decryption + * operation. + * (Encryption and decryption) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param directOut the address for the decrypted data + * @param out buffer for the decrypted data + * @param outOfs buffer offset for the decrypted data + * @param outLen buffer size for the decrypted data + * @return the length of this last part of decrypted data + * (PKCS#11 param: CK_BYTE_PTR pLastPart, + * CK_ULONG_PTR pulLastPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native int C_DecryptFinal(long hSession, long directOut, byte[] out, + int outOfs, int outLen) throws PKCS11Exception; + + + +/* ***************************************************************************** + * Message digesting + ******************************************************************************/ + + /** + * C_DigestInit initializes a message-digesting operation. + * (Message digesting) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the digesting mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_DigestInit(long hSession, CK_MECHANISM pMechanism) + throws PKCS11Exception; + + + // note that C_DigestSingle does not exist in PKCS#11 + // we combined the C_DigestInit and C_Digest into a single function + // to save on Java<->C transitions and save 5-10% on small digests + // this made the C_Digest method redundant, it has been removed + /** + * C_Digest digests data in a single part. + * (Message digesting) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param data the data to get digested and the data's length + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG ulDataLen) + * @return the message digest and the length of the message digest + * (PKCS#11 param: CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (data <> null) + * @postconditions (result <> null) + */ + public native int C_DigestSingle(long hSession, CK_MECHANISM pMechanism, + byte[] in, int inOfs, int inLen, byte[] digest, int digestOfs, + int digestLen) throws PKCS11Exception; + + + /** + * C_DigestUpdate continues a multiple-part message-digesting + * operation. + * (Message digesting) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pPart the data to get digested and the data's length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG ulPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pPart <> null) + * @postconditions + */ + public native void C_DigestUpdate(long hSession, long directIn, byte[] in, + int inOfs, int inLen) throws PKCS11Exception; + + + /** + * C_DigestKey continues a multi-part message-digesting + * operation, by digesting the value of a secret key as part of + * the data already digested. + * (Message digesting) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param hKey the handle of the secret key to be digested + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_DigestKey(long hSession, long hKey) + throws PKCS11Exception; + + + /** + * C_DigestFinal finishes a multiple-part message-digesting + * operation. + * (Message digesting) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @return the message digest and the length of the message digest + * (PKCS#11 param: CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native int C_DigestFinal(long hSession, byte[] pDigest, int digestOfs, + int digestLen) throws PKCS11Exception; + + + +/* ***************************************************************************** + * Signing and MACing + ******************************************************************************/ + + /** + * C_SignInit initializes a signature (private key encryption) + * operation, where the signature is (will be) an appendix to + * the data, and plaintext cannot be recovered from the + * signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the signature mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hKey the handle of the signature key + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_SignInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception; + + + /** + * C_Sign signs (encrypts with private key) data in a single + * part, where the signature is (will be) an appendix to the + * data, and plaintext cannot be recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pData the data to sign and the data's length + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG ulDataLen) + * @return the signature and the signature's length + * (PKCS#11 param: CK_BYTE_PTR pSignature, + * CK_ULONG_PTR pulSignatureLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pData <> null) + * @postconditions (result <> null) + */ + public native byte[] C_Sign(long hSession, byte[] pData) + throws PKCS11Exception; + + + /** + * C_SignUpdate continues a multiple-part signature operation, + * where the signature is (will be) an appendix to the data, + * and plaintext cannot be recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pPart the data part to sign and the data part's length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG ulPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pPart <> null) + * @postconditions + */ + public native void C_SignUpdate(long hSession, long directIn, byte[] in, + int inOfs, int inLen) throws PKCS11Exception; + + + /** + * C_SignFinal finishes a multiple-part signature operation, + * returning the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param expectedLen expected signature length, can be 0 if unknown + * @return the signature and the signature's length + * (PKCS#11 param: CK_BYTE_PTR pSignature, + * CK_ULONG_PTR pulSignatureLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native byte[] C_SignFinal(long hSession, int expectedLen) + throws PKCS11Exception; + + + /** + * C_SignRecoverInit initializes a signature operation, where + * the data can be recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the signature mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hKey the handle of the signature key + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_SignRecoverInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception; + + + /** + * C_SignRecover signs data in a single operation, where the + * data can be recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pData the data to sign and the data's length + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG ulDataLen) + * @return the signature and the signature's length + * (PKCS#11 param: CK_BYTE_PTR pSignature, + * CK_ULONG_PTR pulSignatureLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pData <> null) + * @postconditions (result <> null) + */ + public native int C_SignRecover(long hSession, byte[] in, int inOfs, + int inLen, byte[] out, int outOufs, int outLen) + throws PKCS11Exception; + + + +/* ***************************************************************************** + * Verifying signatures and MACs + ******************************************************************************/ + + /** + * C_VerifyInit initializes a verification operation, where the + * signature is an appendix to the data, and plaintext cannot + * cannot be recovered from the signature (e.g. DSA). + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the verification mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hKey the handle of the verification key + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_VerifyInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception; + + + /** + * C_Verify verifies a signature in a single-part operation, + * where the signature is an appendix to the data, and plaintext + * cannot be recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pData the signed data and the signed data's length + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG ulDataLen) + * @param pSignature the signature to verify and the signature's length + * (PKCS#11 param: CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pData <> null) and (pSignature <> null) + * @postconditions + */ + public native void C_Verify(long hSession, byte[] pData, byte[] pSignature) + throws PKCS11Exception; + + + /** + * C_VerifyUpdate continues a multiple-part verification + * operation, where the signature is an appendix to the data, + * and plaintext cannot be recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pPart the signed data part and the signed data part's length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG ulPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pPart <> null) + * @postconditions + */ + public native void C_VerifyUpdate(long hSession, long directIn, byte[] in, + int inOfs, int inLen) throws PKCS11Exception; + + + /** + * C_VerifyFinal finishes a multiple-part verification + * operation, checking the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pSignature the signature to verify and the signature's length + * (PKCS#11 param: CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pSignature <> null) + * @postconditions + */ + public native void C_VerifyFinal(long hSession, byte[] pSignature) + throws PKCS11Exception; + + + /** + * C_VerifyRecoverInit initializes a signature verification + * operation, where the data is recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the verification mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hKey the handle of the verification key + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native void C_VerifyRecoverInit(long hSession, + CK_MECHANISM pMechanism, long hKey) throws PKCS11Exception; + + + /** + * C_VerifyRecover verifies a signature in a single-part + * operation, where the data is recovered from the signature. + * (Signing and MACing) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pSignature the signature to verify and the signature's length + * (PKCS#11 param: CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) + * @return the recovered data and the recovered data's length + * (PKCS#11 param: CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pSignature <> null) + * @postconditions (result <> null) + */ + public native int C_VerifyRecover(long hSession, byte[] in, int inOfs, + int inLen, byte[] out, int outOufs, int outLen) + throws PKCS11Exception; + + + +/* ***************************************************************************** + * Dual-function cryptographic operations + ******************************************************************************/ + + /** + * C_DigestEncryptUpdate continues a multiple-part digesting + * and encryption operation. + * (Dual-function cryptographic operations) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pPart the data part to digest and to encrypt and the data's length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG ulPartLen) + * @return the digested and encrypted data part and the data part's length + * (PKCS#11 param: CK_BYTE_PTR pEncryptedPart, + * CK_ULONG_PTR pulEncryptedPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pPart <> null) + * @postconditions + */ +// public native byte[] C_DigestEncryptUpdate(long hSession, byte[] pPart) +// throws PKCS11Exception; + + + /** + * C_DecryptDigestUpdate continues a multiple-part decryption and + * digesting operation. + * (Dual-function cryptographic operations) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pEncryptedPart the encrypted data part to decrypt and to digest + * and encrypted data part's length + * (PKCS#11 param: CK_BYTE_PTR pEncryptedPart, + * CK_ULONG ulEncryptedPartLen) + * @return the decrypted and digested data part and the data part's length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pEncryptedPart <> null) + * @postconditions + */ +// public native byte[] C_DecryptDigestUpdate(long hSession, +// byte[] pEncryptedPart) throws PKCS11Exception; + + + /** + * C_SignEncryptUpdate continues a multiple-part signing and + * encryption operation. + * (Dual-function cryptographic operations) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pPart the data part to sign and to encrypt and the data part's + * length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG ulPartLen) + * @return the signed and encrypted data part and the data part's length + * (PKCS#11 param: CK_BYTE_PTR pEncryptedPart, + * CK_ULONG_PTR pulEncryptedPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pPart <> null) + * @postconditions + */ +// public native byte[] C_SignEncryptUpdate(long hSession, byte[] pPart) +// throws PKCS11Exception; + + + /** + * C_DecryptVerifyUpdate continues a multiple-part decryption and + * verify operation. + * (Dual-function cryptographic operations) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pEncryptedPart the encrypted data part to decrypt and to verify + * and the data part's length + * (PKCS#11 param: CK_BYTE_PTR pEncryptedPart, + * CK_ULONG ulEncryptedPartLen) + * @return the decrypted and verified data part and the data part's length + * (PKCS#11 param: CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pEncryptedPart <> null) + * @postconditions + */ +// public native byte[] C_DecryptVerifyUpdate(long hSession, +// byte[] pEncryptedPart) throws PKCS11Exception; + + +/* ***************************************************************************** + * Key management + ******************************************************************************/ + + /** + * getNativeKeyInfo gets the key object attributes and values as an opaque + * byte array to be used in createNativeKey method. + * (Key management) + * + * @param hSession the session's handle + * @param hKey key's handle + * @param hWrappingKey key handle for wrapping the extracted sensitive keys. + * -1 if not used. + * @param pWrappingMech mechanism for wrapping the extracted sensitive keys + * @return an opaque byte array containing the key object attributes + * and values + * @exception PKCS11Exception If an internal PKCS#11 function returns other + * value than CKR_OK. + * @preconditions + * @postconditions + */ + public native byte[] getNativeKeyInfo(long hSession, long hKey, + long hWrappingKey, CK_MECHANISM pWrappingMech) throws PKCS11Exception; + + /** + * createNativeKey creates a key object with attributes and values + * specified by parameter as an opaque byte array. + * (Key management) + * + * @param hSession the session's handle + * @param keyInfo opaque byte array containing key object attributes + * and values + * @param hWrappingKey key handle for unwrapping the extracted sensitive keys. + * -1 if not used. + * @param pWrappingMech mechanism for unwrapping the extracted sensitive keys + * @return key object handle + * @exception PKCS11Exception If an internal PKCS#11 function returns other + * value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long createNativeKey(long hSession, byte[] keyInfo, + long hWrappingKey, CK_MECHANISM pWrappingMech) throws PKCS11Exception; + + /** + * C_GenerateKey generates a secret key, creating a new key + * object. + * (Key management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the key generation mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param pTemplate the template for the new key and the number of + * attributes in the template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @return the handle of the new key + * (PKCS#11 param: CK_OBJECT_HANDLE_PTR phKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long C_GenerateKey(long hSession, CK_MECHANISM pMechanism, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception; + + + /** + * C_GenerateKeyPair generates a public-key/private-key pair, + * creating new key objects. + * (Key management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the key generation mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param pPublicKeyTemplate the template for the new public key and the + * number of attributes in the template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pPublicKeyTemplate, + * CK_ULONG ulPublicKeyAttributeCount) + * @param pPrivateKeyTemplate the template for the new private key and the + * number of attributes in the template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pPrivateKeyTemplate + * CK_ULONG ulPrivateKeyAttributeCount) + * @return a long array with exactly two elements and the public key handle + * as the first element and the private key handle as the second + * element + * (PKCS#11 param: CK_OBJECT_HANDLE_PTR phPublicKey, + * CK_OBJECT_HANDLE_PTR phPrivateKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pMechanism <> null) + * @postconditions (result <> null) and (result.length == 2) + */ + public native long[] C_GenerateKeyPair(long hSession, + CK_MECHANISM pMechanism, CK_ATTRIBUTE[] pPublicKeyTemplate, + CK_ATTRIBUTE[] pPrivateKeyTemplate) throws PKCS11Exception; + + + + /** + * C_WrapKey wraps (i.e., encrypts) a key. + * (Key management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the wrapping mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hWrappingKey the handle of the wrapping key + * (PKCS#11 param: CK_OBJECT_HANDLE hWrappingKey) + * @param hKey the handle of the key to be wrapped + * (PKCS#11 param: CK_OBJECT_HANDLE hKey) + * @return the wrapped key and the length of the wrapped key + * (PKCS#11 param: CK_BYTE_PTR pWrappedKey, + * CK_ULONG_PTR pulWrappedKeyLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions (result <> null) + */ + public native byte[] C_WrapKey(long hSession, CK_MECHANISM pMechanism, + long hWrappingKey, long hKey) throws PKCS11Exception; + + + /** + * C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new + * key object. + * (Key management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the unwrapping mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hUnwrappingKey the handle of the unwrapping key + * (PKCS#11 param: CK_OBJECT_HANDLE hUnwrappingKey) + * @param pWrappedKey the wrapped key to unwrap and the wrapped key's length + * (PKCS#11 param: CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen) + * @param pTemplate the template for the new key and the number of + * attributes in the template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @return the handle of the unwrapped key + * (PKCS#11 param: CK_OBJECT_HANDLE_PTR phKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pWrappedKey <> null) + * @postconditions + */ + public native long C_UnwrapKey(long hSession, CK_MECHANISM pMechanism, + long hUnwrappingKey, byte[] pWrappedKey, CK_ATTRIBUTE[] pTemplate) + throws PKCS11Exception; + + + /** + * C_DeriveKey derives a key from a base key, creating a new key + * object. + * (Key management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pMechanism the key derivation mechanism + * (PKCS#11 param: CK_MECHANISM_PTR pMechanism) + * @param hBaseKey the handle of the base key + * (PKCS#11 param: CK_OBJECT_HANDLE hBaseKey) + * @param pTemplate the template for the new key and the number of + * attributes in the template + * (PKCS#11 param: CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) + * @return the handle of the derived key + * (PKCS#11 param: CK_OBJECT_HANDLE_PTR phKey) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long C_DeriveKey(long hSession, CK_MECHANISM pMechanism, + long hBaseKey, CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception; + + + +/* ***************************************************************************** + * Random number generation + ******************************************************************************/ + + /** + * C_SeedRandom mixes additional seed material into the token's + * random number generator. + * (Random number generation) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param pSeed the seed material and the seed material's length + * (PKCS#11 param: CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pSeed <> null) + * @postconditions + */ + public native void C_SeedRandom(long hSession, byte[] pSeed) + throws PKCS11Exception; + + + /** + * C_GenerateRandom generates random data. + * (Random number generation) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @param RandomData receives the random data and the length of RandomData + * is the length of random data to be generated + * (PKCS#11 param: CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (randomData <> null) + * @postconditions + */ + public native void C_GenerateRandom(long hSession, byte[] randomData) + throws PKCS11Exception; + + + +/* ***************************************************************************** + * Parallel function management + ******************************************************************************/ + + /** + * C_GetFunctionStatus is a legacy function; it obtains an + * updated status of a function running in parallel with an + * application. + * (Parallel function management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native void C_GetFunctionStatus(long hSession) +// throws PKCS11Exception; + + + /** + * C_CancelFunction is a legacy function; it cancels a function + * running in parallel. + * (Parallel function management) + * + * @param hSession the session's handle + * (PKCS#11 param: CK_SESSION_HANDLE hSession) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions + * @postconditions + */ +// public native void C_CancelFunction(long hSession) throws PKCS11Exception; + + + +/* ***************************************************************************** + * Functions added in for Cryptoki Version 2.01 or later + ******************************************************************************/ + + /** + * C_WaitForSlotEvent waits for a slot event (token insertion, + * removal, etc.) to occur. + * (General-purpose) + * + * @param flags blocking/nonblocking flag + * (PKCS#11 param: CK_FLAGS flags) + * @param pReserved reserved. Should be null + * (PKCS#11 param: CK_VOID_PTR pReserved) + * @return the slot ID where the event occurred + * (PKCS#11 param: CK_SLOT_ID_PTR pSlot) + * @exception PKCS11Exception If function returns other value than CKR_OK. + * @preconditions (pRserved == null) + * @postconditions + */ +// public native long C_WaitForSlotEvent(long flags, Object pRserved) +// throws PKCS11Exception; + + /** + * Returns the string representation of this object. + * + * @return The string representation of object + */ + public String toString() { + return "Module name: " + pkcs11ModulePath; + } + + /** + * Calls disconnect() to cleanup the native part of the wrapper. Once this + * method is called, this object cannot be used any longer. Any subsequent + * call to a C_* method will result in a runtime exception. + * + * @exception Throwable If finalization fails. + */ + protected void finalize() throws Throwable { + disconnect(); + } + +// PKCS11 subclass that has all methods synchronized and delegating to the +// parent. Used for tokens that only support single threaded access +static class SynchronizedPKCS11 extends PKCS11 { + + SynchronizedPKCS11(String pkcs11ModulePath, String functionListName) + throws IOException { + super(pkcs11ModulePath, functionListName); + } + + synchronized void C_Initialize(Object pInitArgs) throws PKCS11Exception { + super.C_Initialize(pInitArgs); + } + + public synchronized void C_Finalize(Object pReserved) + throws PKCS11Exception { + super.C_Finalize(pReserved); + } + + public synchronized CK_INFO C_GetInfo() throws PKCS11Exception { + return super.C_GetInfo(); + } + + public synchronized long[] C_GetSlotList(boolean tokenPresent) + throws PKCS11Exception { + return super.C_GetSlotList(tokenPresent); + } + + public synchronized CK_SLOT_INFO C_GetSlotInfo(long slotID) + throws PKCS11Exception { + return super.C_GetSlotInfo(slotID); + } + + public synchronized CK_TOKEN_INFO C_GetTokenInfo(long slotID) + throws PKCS11Exception { + return super.C_GetTokenInfo(slotID); + } + + public synchronized long[] C_GetMechanismList(long slotID) + throws PKCS11Exception { + return super.C_GetMechanismList(slotID); + } + + public synchronized CK_MECHANISM_INFO C_GetMechanismInfo(long slotID, + long type) throws PKCS11Exception { + return super.C_GetMechanismInfo(slotID, type); + } + + public synchronized long C_OpenSession(long slotID, long flags, + Object pApplication, CK_NOTIFY Notify) throws PKCS11Exception { + return super.C_OpenSession(slotID, flags, pApplication, Notify); + } + + public synchronized void C_CloseSession(long hSession) + throws PKCS11Exception { + super.C_CloseSession(hSession); + } + + public synchronized CK_SESSION_INFO C_GetSessionInfo(long hSession) + throws PKCS11Exception { + return super.C_GetSessionInfo(hSession); + } + + public synchronized void C_Login(long hSession, long userType, char[] pPin) + throws PKCS11Exception { + super.C_Login(hSession, userType, pPin); + } + + public synchronized void C_Logout(long hSession) throws PKCS11Exception { + super.C_Logout(hSession); + } + + public synchronized long C_CreateObject(long hSession, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + return super.C_CreateObject(hSession, pTemplate); + } + + public synchronized long C_CopyObject(long hSession, long hObject, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + return super.C_CopyObject(hSession, hObject, pTemplate); + } + + public synchronized void C_DestroyObject(long hSession, long hObject) + throws PKCS11Exception { + super.C_DestroyObject(hSession, hObject); + } + + public synchronized void C_GetAttributeValue(long hSession, long hObject, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + super.C_GetAttributeValue(hSession, hObject, pTemplate); + } + + public synchronized void C_SetAttributeValue(long hSession, long hObject, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + super.C_SetAttributeValue(hSession, hObject, pTemplate); + } + + public synchronized void C_FindObjectsInit(long hSession, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + super.C_FindObjectsInit(hSession, pTemplate); + } + + public synchronized long[] C_FindObjects(long hSession, + long ulMaxObjectCount) throws PKCS11Exception { + return super.C_FindObjects(hSession, ulMaxObjectCount); + } + + public synchronized void C_FindObjectsFinal(long hSession) + throws PKCS11Exception { + super.C_FindObjectsFinal(hSession); + } + + public synchronized void C_EncryptInit(long hSession, + CK_MECHANISM pMechanism, long hKey) throws PKCS11Exception { + super.C_EncryptInit(hSession, pMechanism, hKey); + } + + public synchronized int C_Encrypt(long hSession, long directIn, byte[] in, + int inOfs, int inLen, long directOut, byte[] out, int outOfs, int outLen) + throws PKCS11Exception { + return super.C_Encrypt(hSession, directIn, in, inOfs, inLen, + directOut, out, outOfs, outLen); + } + + public synchronized int C_EncryptUpdate(long hSession, long directIn, + byte[] in, int inOfs, int inLen, long directOut, byte[] out, + int outOfs, int outLen) throws PKCS11Exception { + return super.C_EncryptUpdate(hSession, directIn, in, inOfs, inLen, + directOut, out, outOfs, outLen); + } + + public synchronized int C_EncryptFinal(long hSession, long directOut, + byte[] out, int outOfs, int outLen) throws PKCS11Exception { + return super.C_EncryptFinal(hSession, directOut, out, outOfs, outLen); + } + + public synchronized void C_DecryptInit(long hSession, + CK_MECHANISM pMechanism, long hKey) throws PKCS11Exception { + super.C_DecryptInit(hSession, pMechanism, hKey); + } + + public synchronized int C_Decrypt(long hSession, long directIn, + byte[] in, int inOfs, int inLen, long directOut, byte[] out, + int outOfs, int outLen) throws PKCS11Exception { + return super.C_Decrypt(hSession, directIn, in, inOfs, inLen, + directOut, out, outOfs, outLen); + } + + public synchronized int C_DecryptUpdate(long hSession, long directIn, + byte[] in, int inOfs, int inLen, long directOut, byte[] out, + int outOfs, int outLen) throws PKCS11Exception { + return super.C_DecryptUpdate(hSession, directIn, in, inOfs, inLen, + directOut, out, outOfs, outLen); + } + + public synchronized int C_DecryptFinal(long hSession, long directOut, + byte[] out, int outOfs, int outLen) throws PKCS11Exception { + return super.C_DecryptFinal(hSession, directOut, out, outOfs, outLen); + } + + public synchronized void C_DigestInit(long hSession, CK_MECHANISM pMechanism) + throws PKCS11Exception { + super.C_DigestInit(hSession, pMechanism); + } + + public synchronized int C_DigestSingle(long hSession, + CK_MECHANISM pMechanism, byte[] in, int inOfs, int inLen, + byte[] digest, int digestOfs, int digestLen) throws PKCS11Exception { + return super.C_DigestSingle(hSession, pMechanism, in, inOfs, inLen, + digest, digestOfs, digestLen); + } + + public synchronized void C_DigestUpdate(long hSession, long directIn, + byte[] in, int inOfs, int inLen) throws PKCS11Exception { + super.C_DigestUpdate(hSession, directIn, in, inOfs, inLen); + } + + public synchronized void C_DigestKey(long hSession, long hKey) + throws PKCS11Exception { + super.C_DigestKey(hSession, hKey); + } + + public synchronized int C_DigestFinal(long hSession, byte[] pDigest, + int digestOfs, int digestLen) throws PKCS11Exception { + return super.C_DigestFinal(hSession, pDigest, digestOfs, digestLen); + } + + public synchronized void C_SignInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception { + super.C_SignInit(hSession, pMechanism, hKey); + } + + public synchronized byte[] C_Sign(long hSession, byte[] pData) + throws PKCS11Exception { + return super.C_Sign(hSession, pData); + } + + public synchronized void C_SignUpdate(long hSession, long directIn, + byte[] in, int inOfs, int inLen) throws PKCS11Exception { + super.C_SignUpdate(hSession, directIn, in, inOfs, inLen); + } + + public synchronized byte[] C_SignFinal(long hSession, int expectedLen) + throws PKCS11Exception { + return super.C_SignFinal(hSession, expectedLen); + } + + public synchronized void C_SignRecoverInit(long hSession, + CK_MECHANISM pMechanism, long hKey) throws PKCS11Exception { + super.C_SignRecoverInit(hSession, pMechanism, hKey); + } + + public synchronized int C_SignRecover(long hSession, byte[] in, int inOfs, + int inLen, byte[] out, int outOufs, int outLen) + throws PKCS11Exception { + return super.C_SignRecover(hSession, in, inOfs, inLen, out, outOufs, + outLen); + } + + public synchronized void C_VerifyInit(long hSession, CK_MECHANISM pMechanism, + long hKey) throws PKCS11Exception { + super.C_VerifyInit(hSession, pMechanism, hKey); + } + + public synchronized void C_Verify(long hSession, byte[] pData, + byte[] pSignature) throws PKCS11Exception { + super.C_Verify(hSession, pData, pSignature); + } + + public synchronized void C_VerifyUpdate(long hSession, long directIn, + byte[] in, int inOfs, int inLen) throws PKCS11Exception { + super.C_VerifyUpdate(hSession, directIn, in, inOfs, inLen); + } + + public synchronized void C_VerifyFinal(long hSession, byte[] pSignature) + throws PKCS11Exception { + super.C_VerifyFinal(hSession, pSignature); + } + + public synchronized void C_VerifyRecoverInit(long hSession, + CK_MECHANISM pMechanism, long hKey) throws PKCS11Exception { + super.C_VerifyRecoverInit(hSession, pMechanism, hKey); + } + + public synchronized int C_VerifyRecover(long hSession, byte[] in, int inOfs, + int inLen, byte[] out, int outOufs, int outLen) + throws PKCS11Exception { + return super.C_VerifyRecover(hSession, in, inOfs, inLen, out, outOufs, + outLen); + } + + public synchronized long C_GenerateKey(long hSession, + CK_MECHANISM pMechanism, CK_ATTRIBUTE[] pTemplate) + throws PKCS11Exception { + return super.C_GenerateKey(hSession, pMechanism, pTemplate); + } + + public synchronized long[] C_GenerateKeyPair(long hSession, + CK_MECHANISM pMechanism, CK_ATTRIBUTE[] pPublicKeyTemplate, + CK_ATTRIBUTE[] pPrivateKeyTemplate) + throws PKCS11Exception { + return super.C_GenerateKeyPair(hSession, pMechanism, pPublicKeyTemplate, + pPrivateKeyTemplate); + } + + public synchronized byte[] C_WrapKey(long hSession, CK_MECHANISM pMechanism, + long hWrappingKey, long hKey) throws PKCS11Exception { + return super.C_WrapKey(hSession, pMechanism, hWrappingKey, hKey); + } + + public synchronized long C_UnwrapKey(long hSession, CK_MECHANISM pMechanism, + long hUnwrappingKey, byte[] pWrappedKey, CK_ATTRIBUTE[] pTemplate) + throws PKCS11Exception { + return super.C_UnwrapKey(hSession, pMechanism, hUnwrappingKey, + pWrappedKey, pTemplate); + } + + public synchronized long C_DeriveKey(long hSession, CK_MECHANISM pMechanism, + long hBaseKey, CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + return super.C_DeriveKey(hSession, pMechanism, hBaseKey, pTemplate); + } + + public synchronized void C_SeedRandom(long hSession, byte[] pSeed) + throws PKCS11Exception { + super.C_SeedRandom(hSession, pSeed); + } + + public synchronized void C_GenerateRandom(long hSession, byte[] randomData) + throws PKCS11Exception { + super.C_GenerateRandom(hSession, randomData); + } +} +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11Constants.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11Constants.java new file mode 100644 index 0000000..60cd3c4 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11Constants.java @@ -0,0 +1,1306 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +/** + * This interface holds constants of the PKCS#11 v3.00 standard. + * This is mainly the content of the 'pkcs11t.h' header file. + * + * Mapping of primitiv data types to Java types: + *
+ *   TRUE .......................................... true
+ *   FALSE ......................................... false
+ *   CK_BYTE ....................................... byte
+ *   CK_CHAR ....................................... char
+ *   CK_UTF8CHAR ................................... char
+ *   CK_BBOOL ...................................... boolean
+ *   CK_ULONG ...................................... long
+ *   CK_LONG ....................................... long
+ *   CK_FLAGS ...................................... long
+ *   CK_BYTE_PTR ................................... byte[]
+ *   CK_CHAR_PTR ................................... char[]
+ *   CK_UTF8CHAR_PTR ............................... char[]
+ *   CK_ULONG_PTR .................................. long[]
+ *   CK_VOID_PTR ................................... Object[]
+ *   CK_NOTIFICATION ............................... long
+ *   CK_SLOT_ID .................................... long
+ *   CK_SESSION_HANDLE ............................. long
+ *   CK_USER_TYPE .................................. long
+ *   CK_STATE ...................................... long
+ *   CK_OBJECT_HANDLE .............................. long
+ *   CK_OBJECT_CLASS ............................... long
+ *   CK_HW_FEATURE_TYPE ............................ long
+ *   CK_KEY_TYPE ................................... long
+ *   CK_CERTIFICATE_TYPE ........................... long
+ *   CK_ATTRIBUTE_TYPE ............................. long
+ *   CK_MECHANISM_TYPE ............................. long
+ *   CK_RV ......................................... long
+ *   CK_RSA_PKCS_MGF_TYPE .......................... long
+ *   CK_RSA_PKCS_OAEP_SOURCE_TYPE .................. long
+ *   CK_EC_KDF_TYPE ................................ long
+ *   CK_X9_42_DH_KDF_TYPE .......................... long
+ *   CK_RC2_PARAMS ................................. long
+ *   CK_MAC_GENERAL_PARAMS ......................... long
+ *   CK_EXTRACT_PARAMS ............................. long
+ *   CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE .... long
+ *   CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE .............. long
+ *   CK_OTP_PARAM_TYPE / CK_PARAM_TYPE ............. long
+ *   CK_GENERATOR_FUNCTION ......................... long
+ *   CK_JAVA_MIDP_SECURITY_DOMAIN .................. long
+ *   CK_CERTIFICATE_CATEGORY ....................... long
+ *   CK_PROFILE_ID ................................. long
+ *   CK_PRF_DATA_TYPE .............................. long
+ *   CK_SP800_108_DKM_LENGTH_METHOD ................ long
+ *   CK_X3DH_KDF_TYPE .............................. long
+ *   CK_X2RATCHET_KDF_TYPE ......................... long
+ *   CK_XEDDSA_HASH_TYPE ........................... long
+ * 
+ * + * @author Karl Scheibelhofer + * @invariants + */ +public interface PKCS11Constants { + + public static final boolean TRUE = true; + + public static final boolean FALSE = false; + + public static final Object NULL_PTR = null; + + /* some special values for certain CK_ULONG variables */ + + // Cryptoki defines CK_UNAVAILABLE_INFORMATION as (~0UL) + // This means it is 0xffffffff in ILP32/LLP64 but 0xffffffffffffffff in LP64. + // To avoid these differences on the Java side, the native code treats + // CK_UNAVAILABLE_INFORMATION specially and always returns (long)-1 for it. + // See ckULongSpecialToJLong() in pkcs11wrapper.h + public static final long CK_UNAVAILABLE_INFORMATION = -1; + public static final long CK_EFFECTIVELY_INFINITE = 0L; + + /* The following value is always invalid if used as a session */ + /* handle or object handle */ + public static final long CK_INVALID_HANDLE = 0L; + + /* CK_NOTIFICATION enumerates the types of notifications that + * Cryptoki provides to an application */ + /* CK_NOTIFICATION has been changed from an enum to a CK_ULONG + * for v2.0 */ + public static final long CKN_SURRENDER = 0L; + + /* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ + public static final long CKF_TOKEN_PRESENT = 0x00000001L; + public static final long CKF_REMOVABLE_DEVICE = 0x00000002L; + public static final long CKF_HW_SLOT = 0x00000004L; + + /* The flags parameter is defined as follows: + * Bit Flag Mask Meaning + */ + /* has random # generator */ + public static final long CKF_RNG = 0x00000001L; + + /* token is write-protected */ + public static final long CKF_WRITE_PROTECTED = 0x00000002L; + + /* user must login */ + public static final long CKF_LOGIN_REQUIRED = 0x00000004L; + + /* normal user's PIN is set */ + public static final long CKF_USER_PIN_INITIALIZED = 0x00000008L; + + public static final long CKF_RESTORE_KEY_NOT_NEEDED = 0x00000020L; + + public static final long CKF_CLOCK_ON_TOKEN = 0x00000040L; + + public static final long CKF_PROTECTED_AUTHENTICATION_PATH = 0x00000100L; + + public static final long CKF_DUAL_CRYPTO_OPERATIONS = 0x00000200L; + + public static final long CKF_TOKEN_INITIALIZED = 0x00000400L; + + public static final long CKF_SECONDARY_AUTHENTICATION = 0x00000800L; + + public static final long CKF_USER_PIN_COUNT_LOW = 0x00010000L; + + public static final long CKF_USER_PIN_FINAL_TRY = 0x00020000L; + + public static final long CKF_USER_PIN_LOCKED = 0x00040000L; + + public static final long CKF_USER_PIN_TO_BE_CHANGED = 0x00080000L; + + public static final long CKF_SO_PIN_COUNT_LOW = 0x00100000L; + + public static final long CKF_SO_PIN_FINAL_TRY = 0x00200000L; + + public static final long CKF_SO_PIN_LOCKED = 0x00400000L; + + public static final long CKF_SO_PIN_TO_BE_CHANGED = 0x00800000L; + + /* Security Officer */ + public static final long CKU_SO = 0L; + /* Normal user */ + public static final long CKU_USER = 1L; + + /* CK_STATE enumerates the session states */ + public static final long CKS_RO_PUBLIC_SESSION = 0L; + public static final long CKS_RO_USER_FUNCTIONS = 1L; + public static final long CKS_RW_PUBLIC_SESSION = 2L; + public static final long CKS_RW_USER_FUNCTIONS = 3L; + public static final long CKS_RW_SO_FUNCTIONS = 4L; + + /* The flags are defined in the following table: + * Bit Flag Mask Meaning + */ + /* session is r/w */ + public static final long CKF_RW_SESSION = 0x00000002L; + /* no parallel */ + public static final long CKF_SERIAL_SESSION = 0x00000004L; + + + /* The following classes of objects are defined: */ + public static final long CKO_DATA = 0x00000000L; + public static final long CKO_CERTIFICATE = 0x00000001L; + public static final long CKO_PUBLIC_KEY = 0x00000002L; + public static final long CKO_PRIVATE_KEY = 0x00000003L; + public static final long CKO_SECRET_KEY = 0x00000004L; + public static final long CKO_HW_FEATURE = 0x00000005L; + public static final long CKO_DOMAIN_PARAMETERS = 0x00000006L; + public static final long CKO_MECHANISM = 0x00000007L; + public static final long CKO_OTP_KEY = 0x00000008L; + public static final long CKO_PROFILE = 0x00000009L; + + public static final long CKO_VENDOR_DEFINED = 0x80000000L; + + // pseudo object class ANY (for template manager) + public static final long PCKO_ANY = 0x7FFFFF23L; + + /* Uncomment when actually used + // Profile ID's + public static final long CKP_INVALID_ID = 0x00000000L; + public static final long CKP_BASELINE_PROVIDER = 0x00000001L; + public static final long CKP_EXTENDED_PROVIDER = 0x00000002L; + public static final long CKP_AUTHENTICATION_TOKEN = 0x00000003L; + public static final long CKP_PUBLIC_CERTIFICATES_TOKEN = 0x00000004L; + public static final long CKP_VENDOR_DEFINED = 0x80000000L; + + // The following hardware feature types are defined + public static final long CKH_MONOTONIC_COUNTER = 0x00000001L; + public static final long CKH_CLOCK = 0x00000002L; + public static final long CKH_USER_INTERFACE = 0x00000003L; + public static final long CKH_VENDOR_DEFINED = 0x80000000L; + */ + + /* the following key types are defined: */ + public static final long CKK_RSA = 0x00000000L; + public static final long CKK_DSA = 0x00000001L; + public static final long CKK_DH = 0x00000002L; + public static final long CKK_ECDSA /*deprecated*/ = 0x00000003L; + public static final long CKK_EC = 0x00000003L; + public static final long CKK_X9_42_DH = 0x00000004L; + public static final long CKK_KEA = 0x00000005L; + public static final long CKK_GENERIC_SECRET = 0x00000010L; + public static final long CKK_RC2 = 0x00000011L; + public static final long CKK_RC4 = 0x00000012L; + public static final long CKK_DES = 0x00000013L; + public static final long CKK_DES2 = 0x00000014L; + public static final long CKK_DES3 = 0x00000015L; + + public static final long CKK_CAST = 0x00000016L; + public static final long CKK_CAST3 = 0x00000017L; + public static final long CKK_CAST5 /*deprecated*/ = 0x00000018L; + public static final long CKK_CAST128 = 0x00000018L; + public static final long CKK_RC5 = 0x00000019L; + public static final long CKK_IDEA = 0x0000001AL; + public static final long CKK_SKIPJACK = 0x0000001BL; + public static final long CKK_BATON = 0x0000001CL; + public static final long CKK_JUNIPER = 0x0000001DL; + public static final long CKK_CDMF = 0x0000001EL; + public static final long CKK_AES = 0x0000001FL; + public static final long CKK_BLOWFISH = 0x00000020L; + public static final long CKK_TWOFISH = 0x00000021L; + public static final long CKK_SECURID = 0x00000022L; + public static final long CKK_HOTP = 0x00000023L; + public static final long CKK_ACTI = 0x00000024L; + public static final long CKK_CAMELLIA = 0x00000025L; + public static final long CKK_ARIA = 0x00000026L; + + public static final long CKK_MD5_HMAC = 0x00000027L; + public static final long CKK_SHA_1_HMAC = 0x00000028L; + public static final long CKK_RIPEMD128_HMAC = 0x00000029L; + public static final long CKK_RIPEMD160_HMAC = 0x0000002AL; + public static final long CKK_SHA256_HMAC = 0x0000002BL; + public static final long CKK_SHA384_HMAC = 0x0000002CL; + public static final long CKK_SHA512_HMAC = 0x0000002DL; + public static final long CKK_SHA224_HMAC = 0x0000002EL; + + public static final long CKK_SEED = 0x0000002FL; + public static final long CKK_GOSTR3410 = 0x00000030L; + public static final long CKK_GOSTR3411 = 0x00000031L; + public static final long CKK_GOST28147 = 0x00000032L; + public static final long CKK_CHACHA20 = 0x00000033L; + public static final long CKK_POLY1305 = 0x00000034L; + public static final long CKK_AES_XTS = 0x00000035L; + + public static final long CKK_SHA3_224_HMAC = 0x00000036L; + public static final long CKK_SHA3_256_HMAC = 0x00000037L; + public static final long CKK_SHA3_384_HMAC = 0x00000038L; + public static final long CKK_SHA3_512_HMAC = 0x00000039L; + + public static final long CKK_BLAKE2B_160_HMAC = 0x0000003aL; + public static final long CKK_BLAKE2B_256_HMAC = 0x0000003bL; + public static final long CKK_BLAKE2B_384_HMAC = 0x0000003cL; + public static final long CKK_BLAKE2B_512_HMAC = 0x0000003dL; + public static final long CKK_SALSA20 = 0x0000003eL; + public static final long CKK_X2RATCHET = 0x0000003fL; + public static final long CKK_EC_EDWARDS = 0x00000040L; + public static final long CKK_EC_MONTGOMERY = 0x00000041L; + public static final long CKK_HKDF = 0x00000042L; + + public static final long CKK_SHA512_224_HMAC = 0x00000043L; + public static final long CKK_SHA512_256_HMAC = 0x00000044L; + public static final long CKK_SHA512_T_HMAC = 0x00000045L; + + public static final long CKK_VENDOR_DEFINED = 0x80000000L; + + // pseudo key type ANY (for template manager) + public static final long PCKK_ANY = 0x7FFFFF22L; + + public static final long PCKK_HMAC = 0x7FFFFF23L; + public static final long PCKK_SSLMAC = 0x7FFFFF24L; + public static final long PCKK_TLSPREMASTER = 0x7FFFFF25L; + public static final long PCKK_TLSRSAPREMASTER = 0x7FFFFF26L; + public static final long PCKK_TLSMASTER = 0x7FFFFF27L; + + /* Uncomment when actually used + public static final long CK_CERTIFICATE_CATEGORY_UNSPECIFIED = 0L; + public static final long CK_CERTIFICATE_CATEGORY_TOKEN_USER = 1L; + public static final long CK_CERTIFICATE_CATEGORY_AUTHORITY = 2L; + public static final long CK_CERTIFICATE_CATEGORY_OTHER_ENTITY = 3L; + + public static final long CK_SECURITY_DOMAIN_UNSPECIFIED = 0L; + public static final long CK_SECURITY_DOMAIN_MANUFACTURER = 1L; + public static final long CK_SECURITY_DOMAIN_OPERATOR = 2L; + public static final long CK_SECURITY_DOMAIN_THIRD_PARTY = 3L; + */ + + /* The following certificate types are defined: */ + public static final long CKC_X_509 = 0x00000000L; + public static final long CKC_X_509_ATTR_CERT = 0x00000001L; + public static final long CKC_WTLS = 0x00000002L; + public static final long CKC_VENDOR_DEFINED = 0x80000000L; + + /* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which + * consists of an array of values. + */ + public static final long CKF_ARRAY_ATTRIBUTE = 0x40000000L; + + /* Uncomment when actually used + public static final long CK_OTP_FORMAT_DECIMAL = 0L; + public static final long CK_OTP_FORMAT_HEXADECIMAL = 1L; + public static final long CK_OTP_FORMAT_ALPHANUMERIC = 2L; + public static final long CK_OTP_FORMAT_BINARY = 3L; + + public static final long CK_OTP_PARAM_IGNORED = 0L; + public static final long CK_OTP_PARAM_OPTIONAL = 1L; + public static final long CK_OTP_PARAM_MANDATORY = 2L; + */ + + /* The following attribute types are defined: */ + public static final long CKA_CLASS = 0x00000000L; + public static final long CKA_TOKEN = 0x00000001L; + public static final long CKA_PRIVATE = 0x00000002L; + public static final long CKA_LABEL = 0x00000003L; + public static final long CKA_UNIQUE_ID = 0x00000004L; + public static final long CKA_APPLICATION = 0x00000010L; + public static final long CKA_VALUE = 0x00000011L; + public static final long CKA_OBJECT_ID = 0x00000012L; + public static final long CKA_CERTIFICATE_TYPE = 0x00000080L; + public static final long CKA_ISSUER = 0x00000081L; + public static final long CKA_SERIAL_NUMBER = 0x00000082L; + public static final long CKA_AC_ISSUER = 0x00000083L; + public static final long CKA_OWNER = 0x00000084L; + public static final long CKA_ATTR_TYPES = 0x00000085L; + public static final long CKA_TRUSTED = 0x00000086L; + public static final long CKA_CERTIFICATE_CATEGORY + = 0x00000087L; + public static final long CKA_JAVA_MIDP_SECURITY_DOMAIN + = 0x00000088L; + public static final long CKA_URL = 0x00000089L; + public static final long CKA_HASH_OF_SUBJECT_PUBLIC_KEY + = 0x0000008AL; + public static final long CKA_HASH_OF_ISSUER_PUBLIC_KEY + = 0x0000008BL; + public static final long CKA_NAME_HASH_ALGORITHM + = 0x0000008CL; + public static final long CKA_CHECK_VALUE = 0x00000090L; + + public static final long CKA_KEY_TYPE = 0x00000100L; + public static final long CKA_SUBJECT = 0x00000101L; + public static final long CKA_ID = 0x00000102L; + public static final long CKA_SENSITIVE = 0x00000103L; + public static final long CKA_ENCRYPT = 0x00000104L; + public static final long CKA_DECRYPT = 0x00000105L; + public static final long CKA_WRAP = 0x00000106L; + public static final long CKA_UNWRAP = 0x00000107L; + public static final long CKA_SIGN = 0x00000108L; + public static final long CKA_SIGN_RECOVER = 0x00000109L; + public static final long CKA_VERIFY = 0x0000010AL; + public static final long CKA_VERIFY_RECOVER = 0x0000010BL; + public static final long CKA_DERIVE = 0x0000010CL; + public static final long CKA_START_DATE = 0x00000110L; + public static final long CKA_END_DATE = 0x00000111L; + public static final long CKA_MODULUS = 0x00000120L; + public static final long CKA_MODULUS_BITS = 0x00000121L; + public static final long CKA_PUBLIC_EXPONENT = 0x00000122L; + public static final long CKA_PRIVATE_EXPONENT = 0x00000123L; + public static final long CKA_PRIME_1 = 0x00000124L; + public static final long CKA_PRIME_2 = 0x00000125L; + public static final long CKA_EXPONENT_1 = 0x00000126L; + public static final long CKA_EXPONENT_2 = 0x00000127L; + public static final long CKA_COEFFICIENT = 0x00000128L; + public static final long CKA_PUBLIC_KEY_INFO = 0x00000129L; + public static final long CKA_PRIME = 0x00000130L; + public static final long CKA_SUBPRIME = 0x00000131L; + public static final long CKA_BASE = 0x00000132L; + + public static final long CKA_PRIME_BITS = 0x00000133L; + public static final long CKA_SUB_PRIME_BITS = 0x00000134L; + + public static final long CKA_VALUE_BITS = 0x00000160L; + public static final long CKA_VALUE_LEN = 0x00000161L; + public static final long CKA_EXTRACTABLE = 0x00000162L; + public static final long CKA_LOCAL = 0x00000163L; + public static final long CKA_NEVER_EXTRACTABLE = 0x00000164L; + public static final long CKA_ALWAYS_SENSITIVE = 0x00000165L; + public static final long CKA_KEY_GEN_MECHANISM = 0x00000166L; + + public static final long CKA_MODIFIABLE = 0x00000170L; + public static final long CKA_COPYABLE = 0x00000171L; + public static final long CKA_DESTROYABLE = 0x00000172L; + + public static final long CKA_ECDSA_PARAMS /*deprecated*/ = 0x00000180L; + public static final long CKA_EC_PARAMS = 0x00000180L; + public static final long CKA_EC_POINT = 0x00000181L; + + public static final long CKA_SECONDARY_AUTH /*deprecated*/= 0x00000200L; + public static final long CKA_AUTH_PIN_FLAGS /*deprecated*/= 0x00000201L; + public static final long CKA_ALWAYS_AUTHENTICATE = 0x00000202L; + public static final long CKA_WRAP_WITH_TRUSTED = 0x00000210L; + public static final long CKA_WRAP_TEMPLATE = (CKF_ARRAY_ATTRIBUTE|0x00000211L); + public static final long CKA_UNWRAP_TEMPLATE = (CKF_ARRAY_ATTRIBUTE|0x00000212L); + public static final long CKA_DERIVE_TEMPLATE = (CKF_ARRAY_ATTRIBUTE|0x00000213L); + + public static final long CKA_OTP_FORMAT = 0x00000220L; + public static final long CKA_OTP_LENGTH = 0x00000221L; + public static final long CKA_OTP_TIME_INTERVAL = 0x00000222L; + public static final long CKA_OTP_USER_FRIENDLY_MODE = 0x00000223L; + public static final long CKA_OTP_CHALLENGE_REQUIREMENT = 0x00000224L; + public static final long CKA_OTP_TIME_REQUIREMENT = 0x00000225L; + public static final long CKA_OTP_COUNTER_REQUIREMENT = 0x00000226L; + public static final long CKA_OTP_PIN_REQUIREMENT = 0x00000227L; + public static final long CKA_OTP_COUNTER = 0x0000022EL; + public static final long CKA_OTP_TIME = 0x0000022FL; + public static final long CKA_OTP_USER_IDENTIFIER = 0x0000022AL; + public static final long CKA_OTP_SERVICE_IDENTIFIER = 0x0000022BL; + public static final long CKA_OTP_SERVICE_LOGO = 0x0000022CL; + public static final long CKA_OTP_SERVICE_LOGO_TYPE = 0x0000022DL; + + public static final long CKA_GOSTR3410_PARAMS = 0x00000250L; + public static final long CKA_GOSTR3411_PARAMS = 0x00000251L; + public static final long CKA_GOST28147_PARAMS = 0x00000252L; + + public static final long CKA_HW_FEATURE_TYPE = 0x00000300L; + public static final long CKA_RESET_ON_INIT = 0x00000301L; + public static final long CKA_HAS_RESET = 0x00000302L; + + public static final long CKA_PIXEL_X = 0x00000400L; + public static final long CKA_PIXEL_Y = 0x00000401L; + public static final long CKA_RESOLUTION = 0x00000402L; + public static final long CKA_CHAR_ROWS = 0x00000403L; + public static final long CKA_CHAR_COLUMNS = 0x00000404L; + public static final long CKA_COLOR = 0x00000405L; + public static final long CKA_BITS_PER_PIXEL = 0x00000406L; + public static final long CKA_CHAR_SETS = 0x00000480L; + public static final long CKA_ENCODING_METHODS = 0x00000481L; + public static final long CKA_MIME_TYPES = 0x00000482L; + public static final long CKA_MECHANISM_TYPE = 0x00000500L; + public static final long CKA_REQUIRED_CMS_ATTRIBUTES = 0x00000501L; + public static final long CKA_DEFAULT_CMS_ATTRIBUTES = 0x00000502L; + public static final long CKA_SUPPORTED_CMS_ATTRIBUTES = 0x00000503L; + public static final long CKA_ALLOWED_MECHANISMS = (CKF_ARRAY_ATTRIBUTE|0x00000600L); + + public static final long CKA_PROFILE_ID = 0x00000601L; + public static final long CKA_X2RATCHET_BAG = 0x00000602L; + public static final long CKA_X2RATCHET_BAGSIZE = 0x00000603L; + public static final long CKA_X2RATCHET_BOBS1STMSG = 0x00000604L; + public static final long CKA_X2RATCHET_CKR = 0x00000605L; + public static final long CKA_X2RATCHET_CKS = 0x00000606L; + public static final long CKA_X2RATCHET_DHP = 0x00000607L; + public static final long CKA_X2RATCHET_DHR = 0x00000608L; + public static final long CKA_X2RATCHET_DHS = 0x00000609L; + public static final long CKA_X2RATCHET_HKR = 0x0000060aL; + public static final long CKA_X2RATCHET_HKS = 0x0000060bL; + public static final long CKA_X2RATCHET_ISALICE = 0x0000060cL; + public static final long CKA_X2RATCHET_NHKR = 0x0000060dL; + public static final long CKA_X2RATCHET_NHKS = 0x0000060eL; + public static final long CKA_X2RATCHET_NR = 0x0000060fL; + public static final long CKA_X2RATCHET_NS = 0x00000610L; + public static final long CKA_X2RATCHET_PNS = 0x00000611L; + public static final long CKA_X2RATCHET_RK = 0x00000612L; + + public static final long CKA_VENDOR_DEFINED = 0x80000000L; + + /* the following mechanism types are defined: */ + public static final long CKM_RSA_PKCS_KEY_PAIR_GEN = 0x00000000L; + public static final long CKM_RSA_PKCS = 0x00000001L; + public static final long CKM_RSA_9796 = 0x00000002L; + public static final long CKM_RSA_X_509 = 0x00000003L; + + public static final long CKM_MD2_RSA_PKCS = 0x00000004L; + public static final long CKM_MD5_RSA_PKCS = 0x00000005L; + public static final long CKM_SHA1_RSA_PKCS = 0x00000006L; + + public static final long CKM_RIPEMD128_RSA_PKCS = 0x00000007L; + public static final long CKM_RIPEMD160_RSA_PKCS = 0x00000008L; + public static final long CKM_RSA_PKCS_OAEP = 0x00000009L; + + public static final long CKM_RSA_X9_31_KEY_PAIR_GEN = 0x0000000AL; + public static final long CKM_RSA_X9_31 = 0x0000000BL; + public static final long CKM_SHA1_RSA_X9_31 = 0x0000000CL; + public static final long CKM_RSA_PKCS_PSS = 0x0000000DL; + public static final long CKM_SHA1_RSA_PKCS_PSS = 0x0000000EL; + + public static final long CKM_DSA_KEY_PAIR_GEN = 0x00000010L; + public static final long CKM_DSA = 0x00000011L; + public static final long CKM_DSA_SHA1 = 0x00000012L; + public static final long CKM_DSA_SHA224 = 0x00000013L; + public static final long CKM_DSA_SHA256 = 0x00000014L; + public static final long CKM_DSA_SHA384 = 0x00000015L; + public static final long CKM_DSA_SHA512 = 0x00000016L; + public static final long CKM_DSA_SHA3_224 = 0x00000018L; + public static final long CKM_DSA_SHA3_256 = 0x00000019L; + public static final long CKM_DSA_SHA3_384 = 0x0000001AL; + public static final long CKM_DSA_SHA3_512 = 0x0000001BL; + + public static final long CKM_DH_PKCS_KEY_PAIR_GEN = 0x00000020L; + public static final long CKM_DH_PKCS_DERIVE = 0x00000021L; + + public static final long CKM_X9_42_DH_KEY_PAIR_GEN = 0x00000030L; + public static final long CKM_X9_42_DH_DERIVE = 0x00000031L; + public static final long CKM_X9_42_DH_HYBRID_DERIVE = 0x00000032L; + public static final long CKM_X9_42_MQV_DERIVE = 0x00000033L; + + public static final long CKM_SHA256_RSA_PKCS = 0x00000040L; + public static final long CKM_SHA384_RSA_PKCS = 0x00000041L; + public static final long CKM_SHA512_RSA_PKCS = 0x00000042L; + public static final long CKM_SHA256_RSA_PKCS_PSS = 0x00000043L; + public static final long CKM_SHA384_RSA_PKCS_PSS = 0x00000044L; + public static final long CKM_SHA512_RSA_PKCS_PSS = 0x00000045L; + + public static final long CKM_SHA224_RSA_PKCS = 0x00000046L; + public static final long CKM_SHA224_RSA_PKCS_PSS = 0x00000047L; + + public static final long CKM_SHA512_224 = 0x00000048L; + public static final long CKM_SHA512_224_HMAC = 0x00000049L; + public static final long CKM_SHA512_224_HMAC_GENERAL = 0x0000004AL; + public static final long CKM_SHA512_224_KEY_DERIVATION = 0x0000004BL; + public static final long CKM_SHA512_256 = 0x0000004CL; + public static final long CKM_SHA512_256_HMAC = 0x0000004DL; + public static final long CKM_SHA512_256_HMAC_GENERAL = 0x0000004EL; + public static final long CKM_SHA512_256_KEY_DERIVATION = 0x0000004FL; + + public static final long CKM_SHA512_T = 0x00000050L; + public static final long CKM_SHA512_T_HMAC = 0x00000051L; + public static final long CKM_SHA512_T_HMAC_GENERAL = 0x00000052L; + public static final long CKM_SHA512_T_KEY_DERIVATION = 0x00000053L; + + public static final long CKM_SHA3_256_RSA_PKCS = 0x00000060L; + public static final long CKM_SHA3_384_RSA_PKCS = 0x00000061L; + public static final long CKM_SHA3_512_RSA_PKCS = 0x00000062L; + public static final long CKM_SHA3_256_RSA_PKCS_PSS = 0x00000063L; + public static final long CKM_SHA3_384_RSA_PKCS_PSS = 0x00000064L; + public static final long CKM_SHA3_512_RSA_PKCS_PSS = 0x00000065L; + public static final long CKM_SHA3_224_RSA_PKCS = 0x00000066L; + public static final long CKM_SHA3_224_RSA_PKCS_PSS = 0x00000067L; + + public static final long CKM_RC2_KEY_GEN = 0x00000100L; + public static final long CKM_RC2_ECB = 0x00000101L; + public static final long CKM_RC2_CBC = 0x00000102L; + public static final long CKM_RC2_MAC = 0x00000103L; + + public static final long CKM_RC2_MAC_GENERAL = 0x00000104L; + public static final long CKM_RC2_CBC_PAD = 0x00000105L; + + public static final long CKM_RC4_KEY_GEN = 0x00000110L; + public static final long CKM_RC4 = 0x00000111L; + public static final long CKM_DES_KEY_GEN = 0x00000120L; + public static final long CKM_DES_ECB = 0x00000121L; + public static final long CKM_DES_CBC = 0x00000122L; + public static final long CKM_DES_MAC = 0x00000123L; + + public static final long CKM_DES_MAC_GENERAL = 0x00000124L; + public static final long CKM_DES_CBC_PAD = 0x00000125L; + + public static final long CKM_DES2_KEY_GEN = 0x00000130L; + public static final long CKM_DES3_KEY_GEN = 0x00000131L; + public static final long CKM_DES3_ECB = 0x00000132L; + public static final long CKM_DES3_CBC = 0x00000133L; + public static final long CKM_DES3_MAC = 0x00000134L; + + public static final long CKM_DES3_MAC_GENERAL = 0x00000135L; + public static final long CKM_DES3_CBC_PAD = 0x00000136L; + public static final long CKM_DES3_CMAC_GENERAL = 0x00000137L; + public static final long CKM_DES3_CMAC = 0x00000138L; + public static final long CKM_CDMF_KEY_GEN = 0x00000140L; + public static final long CKM_CDMF_ECB = 0x00000141L; + public static final long CKM_CDMF_CBC = 0x00000142L; + public static final long CKM_CDMF_MAC = 0x00000143L; + public static final long CKM_CDMF_MAC_GENERAL = 0x00000144L; + public static final long CKM_CDMF_CBC_PAD = 0x00000145L; + + public static final long CKM_DES_OFB64 = 0x00000150L; + public static final long CKM_DES_OFB8 = 0x00000151L; + public static final long CKM_DES_CFB64 = 0x00000152L; + public static final long CKM_DES_CFB8 = 0x00000153L; + + public static final long CKM_MD2 = 0x00000200L; + + public static final long CKM_MD2_HMAC = 0x00000201L; + public static final long CKM_MD2_HMAC_GENERAL = 0x00000202L; + + public static final long CKM_MD5 = 0x00000210L; + + public static final long CKM_MD5_HMAC = 0x00000211L; + public static final long CKM_MD5_HMAC_GENERAL = 0x00000212L; + + public static final long CKM_SHA_1 = 0x00000220L; + + public static final long CKM_SHA_1_HMAC = 0x00000221L; + public static final long CKM_SHA_1_HMAC_GENERAL = 0x00000222L; + + public static final long CKM_RIPEMD128 = 0x00000230L; + public static final long CKM_RIPEMD128_HMAC = 0x00000231L; + public static final long CKM_RIPEMD128_HMAC_GENERAL = 0x00000232L; + public static final long CKM_RIPEMD160 = 0x00000240L; + public static final long CKM_RIPEMD160_HMAC = 0x00000241L; + public static final long CKM_RIPEMD160_HMAC_GENERAL = 0x00000242L; + + public static final long CKM_SHA256 = 0x00000250L; + public static final long CKM_SHA256_HMAC = 0x00000251L; + public static final long CKM_SHA256_HMAC_GENERAL = 0x00000252L; + public static final long CKM_SHA224 = 0x00000255L; + public static final long CKM_SHA224_HMAC = 0x00000256L; + public static final long CKM_SHA224_HMAC_GENERAL = 0x00000257L; + public static final long CKM_SHA384 = 0x00000260L; + public static final long CKM_SHA384_HMAC = 0x00000261L; + public static final long CKM_SHA384_HMAC_GENERAL = 0x00000262L; + + public static final long CKM_SHA512 = 0x00000270L; + public static final long CKM_SHA512_HMAC = 0x00000271L; + public static final long CKM_SHA512_HMAC_GENERAL = 0x00000272L; + + public static final long CKM_SECURID_KEY_GEN = 0x00000280L; + public static final long CKM_SECURID = 0x00000282L; + public static final long CKM_HOTP_KEY_GEN = 0x00000290L; + public static final long CKM_HOTP = 0x00000291L; + public static final long CKM_ACTI = 0x000002A0L; + public static final long CKM_ACTI_KEY_GEN = 0x000002A1L; + + public static final long CKM_SHA3_256 = 0x000002B0L; + public static final long CKM_SHA3_256_HMAC = 0x000002B1L; + public static final long CKM_SHA3_256_HMAC_GENERAL = 0x000002B2L; + public static final long CKM_SHA3_256_KEY_GEN = 0x000002B3L; + public static final long CKM_SHA3_224 = 0x000002B5L; + public static final long CKM_SHA3_224_HMAC = 0x000002B6L; + public static final long CKM_SHA3_224_HMAC_GENERAL = 0x000002B7L; + public static final long CKM_SHA3_224_KEY_GEN = 0x000002B8L; + public static final long CKM_SHA3_384 = 0x000002C0L; + public static final long CKM_SHA3_384_HMAC = 0x000002C1L; + public static final long CKM_SHA3_384_HMAC_GENERAL = 0x000002C2L; + public static final long CKM_SHA3_384_KEY_GEN = 0x000002C3L; + public static final long CKM_SHA3_512 = 0x000002D0L; + public static final long CKM_SHA3_512_HMAC = 0x000002D1L; + public static final long CKM_SHA3_512_HMAC_GENERAL = 0x000002D2L; + public static final long CKM_SHA3_512_KEY_GEN = 0x000002D3L; + + public static final long CKM_CAST_KEY_GEN = 0x00000300L; + public static final long CKM_CAST_ECB = 0x00000301L; + public static final long CKM_CAST_CBC = 0x00000302L; + public static final long CKM_CAST_MAC = 0x00000303L; + public static final long CKM_CAST_MAC_GENERAL = 0x00000304L; + public static final long CKM_CAST_CBC_PAD = 0x00000305L; + public static final long CKM_CAST3_KEY_GEN = 0x00000310L; + public static final long CKM_CAST3_ECB = 0x00000311L; + public static final long CKM_CAST3_CBC = 0x00000312L; + public static final long CKM_CAST3_MAC = 0x00000313L; + public static final long CKM_CAST3_MAC_GENERAL = 0x00000314L; + public static final long CKM_CAST3_CBC_PAD = 0x00000315L; + /* Note that CAST128 and CAST5 are the same algorithm */ + public static final long CKM_CAST5_KEY_GEN = 0x00000320L; + public static final long CKM_CAST128_KEY_GEN = 0x00000320L; + public static final long CKM_CAST5_ECB = 0x00000321L; + public static final long CKM_CAST128_ECB = 0x00000321L; + public static final long CKM_CAST5_CBC /*deprecated*/ = 0x00000322L; + public static final long CKM_CAST128_CBC = 0x00000322L; + public static final long CKM_CAST5_MAC /*deprecated*/ = 0x00000323L; + public static final long CKM_CAST128_MAC = 0x00000323L; + public static final long CKM_CAST5_MAC_GENERAL /*deprecated*/ + = 0x00000324L; + public static final long CKM_CAST128_MAC_GENERAL = 0x00000324L; + public static final long CKM_CAST5_CBC_PAD /*deprecated*/ = 0x00000325L; + public static final long CKM_CAST128_CBC_PAD = 0x00000325L; + public static final long CKM_RC5_KEY_GEN = 0x00000330L; + public static final long CKM_RC5_ECB = 0x00000331L; + public static final long CKM_RC5_CBC = 0x00000332L; + public static final long CKM_RC5_MAC = 0x00000333L; + public static final long CKM_RC5_MAC_GENERAL = 0x00000334L; + public static final long CKM_RC5_CBC_PAD = 0x00000335L; + public static final long CKM_IDEA_KEY_GEN = 0x00000340L; + public static final long CKM_IDEA_ECB = 0x00000341L; + public static final long CKM_IDEA_CBC = 0x00000342L; + public static final long CKM_IDEA_MAC = 0x00000343L; + public static final long CKM_IDEA_MAC_GENERAL = 0x00000344L; + public static final long CKM_IDEA_CBC_PAD = 0x00000345L; + public static final long CKM_GENERIC_SECRET_KEY_GEN = 0x00000350L; + public static final long CKM_CONCATENATE_BASE_AND_KEY = 0x00000360L; + public static final long CKM_CONCATENATE_BASE_AND_DATA = 0x00000362L; + public static final long CKM_CONCATENATE_DATA_AND_BASE = 0x00000363L; + public static final long CKM_XOR_BASE_AND_DATA = 0x00000364L; + public static final long CKM_EXTRACT_KEY_FROM_KEY = 0x00000365L; + public static final long CKM_SSL3_PRE_MASTER_KEY_GEN = 0x00000370L; + public static final long CKM_SSL3_MASTER_KEY_DERIVE = 0x00000371L; + public static final long CKM_SSL3_KEY_AND_MAC_DERIVE = 0x00000372L; + + public static final long CKM_SSL3_MASTER_KEY_DERIVE_DH = 0x00000373L; + public static final long CKM_TLS_PRE_MASTER_KEY_GEN = 0x00000374L; + public static final long CKM_TLS_MASTER_KEY_DERIVE = 0x00000375L; + public static final long CKM_TLS_KEY_AND_MAC_DERIVE = 0x00000376L; + public static final long CKM_TLS_MASTER_KEY_DERIVE_DH = 0x00000377L; + public static final long CKM_TLS_PRF = 0x00000378L; + + public static final long CKM_SSL3_MD5_MAC = 0x00000380L; + public static final long CKM_SSL3_SHA1_MAC = 0x00000381L; + public static final long CKM_MD5_KEY_DERIVATION = 0x00000390L; + public static final long CKM_MD2_KEY_DERIVATION = 0x00000391L; + public static final long CKM_SHA1_KEY_DERIVATION = 0x00000392L; + public static final long CKM_SHA256_KEY_DERIVATION = 0x00000393L; + public static final long CKM_SHA384_KEY_DERIVATION = 0x00000394L; + public static final long CKM_SHA512_KEY_DERIVATION = 0x00000395L; + public static final long CKM_SHA224_KEY_DERIVATION = 0x00000396L; + public static final long CKM_SHA3_256_KEY_DERIVATION = 0x00000397L; + public static final long CKM_SHA3_224_KEY_DERIVATION = 0x00000398L; + public static final long CKM_SHA3_384_KEY_DERIVATION = 0x00000399L; + public static final long CKM_SHA3_512_KEY_DERIVATION = 0x0000039AL; + public static final long CKM_SHAKE_128_KEY_DERIVATION = 0x0000039BL; + public static final long CKM_SHAKE_256_KEY_DERIVATION = 0x0000039CL; + + public static final long CKM_PBE_MD2_DES_CBC = 0x000003A0L; + public static final long CKM_PBE_MD5_DES_CBC = 0x000003A1L; + public static final long CKM_PBE_MD5_CAST_CBC = 0x000003A2L; + public static final long CKM_PBE_MD5_CAST3_CBC = 0x000003A3L; + public static final long CKM_PBE_MD5_CAST5_CBC /*deprecated*/ + = 0x000003A4L; + public static final long CKM_PBE_MD5_CAST128_CBC = 0x000003A4L; + public static final long CKM_PBE_SHA1_CAST5_CBC /*deprecated*/ + = 0x000003A5L; + public static final long CKM_PBE_SHA1_CAST128_CBC = 0x000003A5L; + public static final long CKM_PBE_SHA1_RC4_128 = 0x000003A6L; + public static final long CKM_PBE_SHA1_RC4_40 = 0x000003A7L; + public static final long CKM_PBE_SHA1_DES3_EDE_CBC = 0x000003A8L; + public static final long CKM_PBE_SHA1_DES2_EDE_CBC = 0x000003A9L; + public static final long CKM_PBE_SHA1_RC2_128_CBC = 0x000003AAL; + public static final long CKM_PBE_SHA1_RC2_40_CBC = 0x000003ABL; + + public static final long CKM_PKCS5_PBKD2 = 0x000003B0L; + + public static final long CKM_PBA_SHA1_WITH_SHA1_HMAC = 0x000003C0L; + + public static final long CKM_WTLS_PRE_MASTER_KEY_GEN = 0x000003D0L; + public static final long CKM_WTLS_MASTER_KEY_DERIVE = 0x000003D1L; + public static final long CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC = 0x000003D2L; + public static final long CKM_WTLS_PRF = 0x000003D3L; + public static final long CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE = 0x000003D4L; + public static final long CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE = 0x000003D5L; + + public static final long CKM_TLS10_MAC_SERVER /*removed in 3.00*/ + = 0x000003D6L; + public static final long CKM_TLS10_MAC_CLIENT /*removed in 3.00*/ + = 0x000003D7L; + public static final long CKM_TLS12_MAC = 0x000003D8L; + public static final long CKM_TLS12_KDF = 0x000003D9L; + public static final long CKM_TLS12_MASTER_KEY_DERIVE = 0x000003E0L; + public static final long CKM_TLS12_KEY_AND_MAC_DERIVE = 0x000003E1L; + public static final long CKM_TLS12_MASTER_KEY_DERIVE_DH = 0x000003E2L; + public static final long CKM_TLS12_KEY_SAFE_DERIVE = 0x000003E3L; + public static final long CKM_TLS_MAC = 0x000003E4L; + public static final long CKM_TLS_KDF = 0x000003E5L; + + public static final long CKM_KEY_WRAP_LYNKS = 0x00000400L; + public static final long CKM_KEY_WRAP_SET_OAEP = 0x00000401L; + + public static final long CKM_CMS_SIG = 0x00000500L; + public static final long CKM_KIP_DERIVE = 0x00000510L; + public static final long CKM_KIP_WRAP = 0x00000511L; + public static final long CKM_KIP_MAC = 0x00000512L; + + public static final long CKM_CAMELLIA_KEY_GEN = 0x00000550L; + public static final long CKM_CAMELLIA_ECB = 0x00000551L; + public static final long CKM_CAMELLIA_CBC = 0x00000552L; + public static final long CKM_CAMELLIA_MAC = 0x00000553L; + public static final long CKM_CAMELLIA_MAC_GENERAL = 0x00000554L; + public static final long CKM_CAMELLIA_CBC_PAD = 0x00000555L; + public static final long CKM_CAMELLIA_ECB_ENCRYPT_DATA = 0x00000556L; + public static final long CKM_CAMELLIA_CBC_ENCRYPT_DATA = 0x00000557L; + public static final long CKM_CAMELLIA_CTR = 0x00000558L; + + public static final long CKM_ARIA_KEY_GEN = 0x00000560L; + public static final long CKM_ARIA_ECB = 0x00000561L; + public static final long CKM_ARIA_CBC = 0x00000562L; + public static final long CKM_ARIA_MAC = 0x00000563L; + public static final long CKM_ARIA_MAC_GENERAL = 0x00000564L; + public static final long CKM_ARIA_CBC_PAD = 0x00000565L; + public static final long CKM_ARIA_ECB_ENCRYPT_DATA = 0x00000566L; + public static final long CKM_ARIA_CBC_ENCRYPT_DATA = 0x00000567L; + + public static final long CKM_SEED_KEY_GEN = 0x00000650L; + public static final long CKM_SEED_ECB = 0x00000651L; + public static final long CKM_SEED_CBC = 0x00000652L; + public static final long CKM_SEED_MAC = 0x00000653L; + public static final long CKM_SEED_MAC_GENERAL = 0x00000654L; + public static final long CKM_SEED_CBC_PAD = 0x00000655L; + public static final long CKM_SEED_ECB_ENCRYPT_DATA = 0x00000656L; + public static final long CKM_SEED_CBC_ENCRYPT_DATA = 0x00000657L; + + public static final long CKM_SKIPJACK_KEY_GEN = 0x00001000L; + public static final long CKM_SKIPJACK_ECB64 = 0x00001001L; + public static final long CKM_SKIPJACK_CBC64 = 0x00001002L; + public static final long CKM_SKIPJACK_OFB64 = 0x00001003L; + public static final long CKM_SKIPJACK_CFB64 = 0x00001004L; + public static final long CKM_SKIPJACK_CFB32 = 0x00001005L; + public static final long CKM_SKIPJACK_CFB16 = 0x00001006L; + public static final long CKM_SKIPJACK_CFB8 = 0x00001007L; + public static final long CKM_SKIPJACK_WRAP = 0x00001008L; + public static final long CKM_SKIPJACK_PRIVATE_WRAP = 0x00001009L; + public static final long CKM_SKIPJACK_RELAYX = 0x0000100AL; + public static final long CKM_KEA_KEY_PAIR_GEN = 0x00001010L; + public static final long CKM_KEA_KEY_DERIVE = 0x00001011L; + public static final long CKM_KEA_DERIVE = 0x00001012L; + public static final long CKM_FORTEZZA_TIMESTAMP = 0x00001020L; + public static final long CKM_BATON_KEY_GEN = 0x00001030L; + public static final long CKM_BATON_ECB128 = 0x00001031L; + public static final long CKM_BATON_ECB96 = 0x00001032L; + public static final long CKM_BATON_CBC128 = 0x00001033L; + public static final long CKM_BATON_COUNTER = 0x00001034L; + public static final long CKM_BATON_SHUFFLE = 0x00001035L; + public static final long CKM_BATON_WRAP = 0x00001036L; + + public static final long CKM_ECDSA_KEY_PAIR_GEN /*deprecated*/ + = 0x00001040L; + public static final long CKM_EC_KEY_PAIR_GEN = 0x00001040L; + public static final long CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS = 0x0000140BL; + + public static final long CKM_ECDSA = 0x00001041L; + public static final long CKM_ECDSA_SHA1 = 0x00001042L; + public static final long CKM_ECDSA_SHA224 = 0x00001043L; + public static final long CKM_ECDSA_SHA256 = 0x00001044L; + public static final long CKM_ECDSA_SHA384 = 0x00001045L; + public static final long CKM_ECDSA_SHA512 = 0x00001046L; + public static final long CKM_ECDSA_SHA3_224 = 0x00001047L; + public static final long CKM_ECDSA_SHA3_256 = 0x00001048L; + public static final long CKM_ECDSA_SHA3_384 = 0x00001049L; + public static final long CKM_ECDSA_SHA3_512 = 0x0000104AL; + + public static final long CKM_ECDH1_DERIVE = 0x00001050L; + public static final long CKM_ECDH1_COFACTOR_DERIVE = 0x00001051L; + public static final long CKM_ECMQV_DERIVE = 0x00001052L; + + public static final long CKM_ECDH_AES_KEY_WRAP = 0x00001053L; + public static final long CKM_RSA_AES_KEY_WRAP = 0x00001054L; + + public static final long CKM_EC_EDWARDS_KEY_PAIR_GEN = 0x00001055L; + public static final long CKM_EC_MONTGOMERY_KEY_PAIR_GEN = 0x00001056L; + public static final long CKM_EDDSA = 0x00001057L; + + public static final long CKM_JUNIPER_KEY_GEN = 0x00001060L; + public static final long CKM_JUNIPER_ECB128 = 0x00001061L; + public static final long CKM_JUNIPER_CBC128 = 0x00001062L; + public static final long CKM_JUNIPER_COUNTER = 0x00001063L; + public static final long CKM_JUNIPER_SHUFFLE = 0x00001064L; + public static final long CKM_JUNIPER_WRAP = 0x00001065L; + public static final long CKM_FASTHASH = 0x00001070L; + + public static final long CKM_AES_XTS = 0x00001071L; + public static final long CKM_AES_XTS_KEY_GEN = 0x00001072L; + public static final long CKM_AES_KEY_GEN = 0x00001080L; + public static final long CKM_AES_ECB = 0x00001081L; + public static final long CKM_AES_CBC = 0x00001082L; + public static final long CKM_AES_MAC = 0x00001083L; + public static final long CKM_AES_MAC_GENERAL = 0x00001084L; + public static final long CKM_AES_CBC_PAD = 0x00001085L; + public static final long CKM_AES_CTR = 0x00001086L; + public static final long CKM_AES_GCM = 0x00001087L; + public static final long CKM_AES_CCM = 0x00001088L; + public static final long CKM_AES_CTS = 0x00001089L; + public static final long CKM_AES_CMAC = 0x0000108AL; + public static final long CKM_AES_CMAC_GENERAL = 0x0000108BL; + + public static final long CKM_AES_XCBC_MAC = 0x0000108CL; + public static final long CKM_AES_XCBC_MAC_96 = 0x0000108DL; + public static final long CKM_AES_GMAC = 0x0000108EL; + + public static final long CKM_BLOWFISH_KEY_GEN = 0x00001090L; + public static final long CKM_BLOWFISH_CBC = 0x00001091L; + public static final long CKM_TWOFISH_KEY_GEN = 0x00001092L; + public static final long CKM_TWOFISH_CBC = 0x00001093L; + public static final long CKM_BLOWFISH_CBC_PAD = 0x00001094L; + public static final long CKM_TWOFISH_CBC_PAD = 0x00001095L; + + public static final long CKM_DES_ECB_ENCRYPT_DATA = 0x00001100L; + public static final long CKM_DES_CBC_ENCRYPT_DATA = 0x00001101L; + public static final long CKM_DES3_ECB_ENCRYPT_DATA = 0x00001102L; + public static final long CKM_DES3_CBC_ENCRYPT_DATA = 0x00001103L; + public static final long CKM_AES_ECB_ENCRYPT_DATA = 0x00001104L; + public static final long CKM_AES_CBC_ENCRYPT_DATA = 0x00001105L; + + public static final long CKM_GOSTR3410_KEY_PAIR_GEN = 0x00001200L; + public static final long CKM_GOSTR3410 = 0x00001201L; + public static final long CKM_GOSTR3410_WITH_GOSTR3411 = 0x00001202L; + public static final long CKM_GOSTR3410_KEY_WRAP = 0x00001203L; + public static final long CKM_GOSTR3410_DERIVE = 0x00001204L; + public static final long CKM_GOSTR3411 = 0x00001210L; + public static final long CKM_GOSTR3411_HMAC = 0x00001211L; + public static final long CKM_GOST28147_KEY_GEN = 0x00001220L; + public static final long CKM_GOST28147_ECB = 0x00001221L; + public static final long CKM_GOST28147 = 0x00001222L; + public static final long CKM_GOST28147_MAC = 0x00001223L; + public static final long CKM_GOST28147_KEY_WRAP = 0x00001224L; + + public static final long CKM_CHACHA20_KEY_GEN = 0x00001225L; + public static final long CKM_CHACHA20 = 0x00001226L; + public static final long CKM_POLY1305_KEY_GEN = 0x00001227L; + public static final long CKM_POLY1305 = 0x00001228L; + + public static final long CKM_DSA_PARAMETER_GEN = 0x00002000L; + public static final long CKM_DH_PKCS_PARAMETER_GEN = 0x00002001L; + public static final long CKM_X9_42_DH_PARAMETER_GEN = 0x00002002L; + public static final long CKM_DSA_PROBABLISTIC_PARAMETER_GEN = 0x00002003L; + public static final long CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN = 0x00002004L; + public static final long CKM_DSA_FIPS_G_GEN = 0x00002005L; + + public static final long CKM_AES_OFB = 0x00002104L; + public static final long CKM_AES_CFB64 = 0x00002105L; + public static final long CKM_AES_CFB8 = 0x00002106L; + public static final long CKM_AES_CFB128 = 0x00002107L; + public static final long CKM_AES_CFB1 = 0x00002108L; + public static final long CKM_AES_KEY_WRAP /* WAS: 0x00001090 */ + = 0x00002109L; + public static final long CKM_AES_KEY_WRAP_PAD /* WAS: 0x00001091 */ + = 0x0000210AL; + public static final long CKM_AES_KEY_WRAP_KWP = 0x0000210BL; + + public static final long CKM_RSA_PKCS_TPM_1_1 = 0x00004001L; + public static final long CKM_RSA_PKCS_OAEP_TPM_1_1 = 0x00004002L; + + public static final long CKM_SHA_1_KEY_GEN = 0x00004003L; + public static final long CKM_SHA224_KEY_GEN = 0x00004004L; + public static final long CKM_SHA256_KEY_GEN = 0x00004005L; + public static final long CKM_SHA384_KEY_GEN = 0x00004006L; + public static final long CKM_SHA512_KEY_GEN = 0x00004007L; + public static final long CKM_SHA512_224_KEY_GEN = 0x00004008L; + public static final long CKM_SHA512_256_KEY_GEN = 0x00004009L; + public static final long CKM_SHA512_T_KEY_GEN = 0x0000400aL; + public static final long CKM_NULL = 0x0000400bL; + public static final long CKM_BLAKE2B_160 = 0x0000400cL; + public static final long CKM_BLAKE2B_160_HMAC = 0x0000400dL; + public static final long CKM_BLAKE2B_160_HMAC_GENERAL = 0x0000400eL; + public static final long CKM_BLAKE2B_160_KEY_DERIVE = 0x0000400fL; + public static final long CKM_BLAKE2B_160_KEY_GEN = 0x00004010L; + public static final long CKM_BLAKE2B_256 = 0x00004011L; + public static final long CKM_BLAKE2B_256_HMAC = 0x00004012L; + public static final long CKM_BLAKE2B_256_HMAC_GENERAL = 0x00004013L; + public static final long CKM_BLAKE2B_256_KEY_DERIVE = 0x00004014L; + public static final long CKM_BLAKE2B_256_KEY_GEN = 0x00004015L; + public static final long CKM_BLAKE2B_384 = 0x00004016L; + public static final long CKM_BLAKE2B_384_HMAC = 0x00004017L; + public static final long CKM_BLAKE2B_384_HMAC_GENERAL = 0x00004018L; + public static final long CKM_BLAKE2B_384_KEY_DERIVE = 0x00004019L; + public static final long CKM_BLAKE2B_384_KEY_GEN = 0x0000401aL; + public static final long CKM_BLAKE2B_512 = 0x0000401bL; + public static final long CKM_BLAKE2B_512_HMAC = 0x0000401cL; + public static final long CKM_BLAKE2B_512_HMAC_GENERAL = 0x0000401dL; + public static final long CKM_BLAKE2B_512_KEY_DERIVE = 0x0000401eL; + public static final long CKM_BLAKE2B_512_KEY_GEN = 0x0000401fL; + public static final long CKM_SALSA20 = 0x00004020L; + public static final long CKM_CHACHA20_POLY1305 = 0x00004021L; + public static final long CKM_SALSA20_POLY1305 = 0x00004022L; + public static final long CKM_X3DH_INITIALIZE = 0x00004023L; + public static final long CKM_X3DH_RESPOND = 0x00004024L; + public static final long CKM_X2RATCHET_INITIALIZE = 0x00004025L; + public static final long CKM_X2RATCHET_RESPOND = 0x00004026L; + public static final long CKM_X2RATCHET_ENCRYPT = 0x00004027L; + public static final long CKM_X2RATCHET_DECRYPT = 0x00004028L; + public static final long CKM_XEDDSA = 0x00004029L; + public static final long CKM_HKDF_DERIVE = 0x0000402aL; + public static final long CKM_HKDF_DATA = 0x0000402bL; + public static final long CKM_HKDF_KEY_GEN = 0x0000402cL; + public static final long CKM_SALSA20_KEY_GEN = 0x0000402dL; + + public static final long CKM_SP800_108_COUNTER_KDF = 0x000003acL; + public static final long CKM_SP800_108_FEEDBACK_KDF = 0x000003adL; + public static final long CKM_SP800_108_DOUBLE_PIPELINE_KDF = 0x000003aeL; + + public static final long CKM_VENDOR_DEFINED = 0x80000000L; + + // NSS private + public static final long CKM_NSS_TLS_PRF_GENERAL = 0x80000373L; + + // internal ids for our pseudo mechanisms SecureRandom and KeyStore + public static final long PCKM_SECURERANDOM = 0x7FFFFF20L; + public static final long PCKM_KEYSTORE = 0x7FFFFF21L; + + /* The flags specify whether or not a mechanism can be used for a + * particular task */ + public static final long CKF_HW = 0x00000001L; + public static final long CKF_MESSAGE_ENCRYPT = 0x00000002L; + public static final long CKF_MESSAGE_DECRYPT = 0x00000004L; + public static final long CKF_MESSAGE_SIGN = 0x00000008L; + public static final long CKF_MESSAGE_VERIFY = 0x00000010L; + public static final long CKF_MULTI_MESSAGE = 0x00000020L; + public static final long CKF_FIND_OBJECTS = 0x00000040L; + + public static final long CKF_ENCRYPT = 0x00000100L; + public static final long CKF_DECRYPT = 0x00000200L; + public static final long CKF_DIGEST = 0x00000400L; + public static final long CKF_SIGN = 0x00000800L; + public static final long CKF_SIGN_RECOVER = 0x00001000L; + public static final long CKF_VERIFY = 0x00002000L; + public static final long CKF_VERIFY_RECOVER = 0x00004000L; + public static final long CKF_GENERATE = 0x00008000L; + public static final long CKF_GENERATE_KEY_PAIR = 0x00010000L; + public static final long CKF_WRAP = 0x00020000L; + public static final long CKF_UNWRAP = 0x00040000L; + public static final long CKF_DERIVE = 0x00080000L; + + /* Describe a token's EC capabilities not available in mechanism + * information. + */ + public static final long CKF_EC_F_P = 0x00100000L; + public static final long CKF_EC_F_2M = 0x00200000L; + public static final long CKF_EC_ECPARAMETERS = 0x00400000L; + public static final long CKF_EC_OID = 0x00400000L; + public static final long CKF_EC_NAMEDCURVE /*deprecated since 3.00*/ + = CKF_EC_OID; + public static final long CKF_EC_UNCOMPRESS = 0x01000000L; + public static final long CKF_EC_COMPRESS = 0x02000000L; + public static final long CKF_EC_CURVENAME = 0x04000000L; + + public static final long CKF_EXTENSION = 0x80000000L; + + /* Identifies the return value of a Cryptoki function */ + public static final long CKR_OK = 0x00000000L; + public static final long CKR_CANCEL = 0x00000001L; + public static final long CKR_HOST_MEMORY = 0x00000002L; + public static final long CKR_SLOT_ID_INVALID = 0x00000003L; + + public static final long CKR_GENERAL_ERROR = 0x00000005L; + public static final long CKR_FUNCTION_FAILED = 0x00000006L; + + public static final long CKR_ARGUMENTS_BAD = 0x00000007L; + public static final long CKR_NO_EVENT = 0x00000008L; + public static final long CKR_NEED_TO_CREATE_THREADS + = 0x00000009L; + public static final long CKR_CANT_LOCK = 0x0000000AL; + + public static final long CKR_ATTRIBUTE_READ_ONLY = 0x00000010L; + public static final long CKR_ATTRIBUTE_SENSITIVE = 0x00000011L; + public static final long CKR_ATTRIBUTE_TYPE_INVALID = 0x00000012L; + public static final long CKR_ATTRIBUTE_VALUE_INVALID = 0x00000013L; + public static final long CKR_ACTION_PROHIBITED = 0x0000001BL; + + public static final long CKR_DATA_INVALID = 0x00000020L; + public static final long CKR_DATA_LEN_RANGE = 0x00000021L; + public static final long CKR_DEVICE_ERROR = 0x00000030L; + public static final long CKR_DEVICE_MEMORY = 0x00000031L; + public static final long CKR_DEVICE_REMOVED = 0x00000032L; + public static final long CKR_ENCRYPTED_DATA_INVALID = 0x00000040L; + public static final long CKR_ENCRYPTED_DATA_LEN_RANGE = 0x00000041L; + public static final long CKR_AEAD_DECRYPT_FAILED = 0x00000042L; + public static final long CKR_FUNCTION_CANCELED = 0x00000050L; + public static final long CKR_FUNCTION_NOT_PARALLEL = 0x00000051L; + + public static final long CKR_FUNCTION_NOT_SUPPORTED = 0x00000054L; + + public static final long CKR_KEY_HANDLE_INVALID = 0x00000060L; + + public static final long CKR_KEY_SIZE_RANGE = 0x00000062L; + public static final long CKR_KEY_TYPE_INCONSISTENT = 0x00000063L; + + public static final long CKR_KEY_NOT_NEEDED = 0x00000064L; + public static final long CKR_KEY_CHANGED = 0x00000065L; + public static final long CKR_KEY_NEEDED = 0x00000066L; + public static final long CKR_KEY_INDIGESTIBLE = 0x00000067L; + public static final long CKR_KEY_FUNCTION_NOT_PERMITTED = 0x00000068L; + public static final long CKR_KEY_NOT_WRAPPABLE = 0x00000069L; + public static final long CKR_KEY_UNEXTRACTABLE = 0x0000006AL; + + public static final long CKR_MECHANISM_INVALID = 0x00000070L; + public static final long CKR_MECHANISM_PARAM_INVALID = 0x00000071L; + + public static final long CKR_OBJECT_HANDLE_INVALID = 0x00000082L; + public static final long CKR_OPERATION_ACTIVE = 0x00000090L; + public static final long CKR_OPERATION_NOT_INITIALIZED = 0x00000091L; + public static final long CKR_PIN_INCORRECT = 0x000000A0L; + public static final long CKR_PIN_INVALID = 0x000000A1L; + public static final long CKR_PIN_LEN_RANGE = 0x000000A2L; + + public static final long CKR_PIN_EXPIRED = 0x000000A3L; + public static final long CKR_PIN_LOCKED = 0x000000A4L; + + public static final long CKR_SESSION_CLOSED = 0x000000B0L; + public static final long CKR_SESSION_COUNT = 0x000000B1L; + public static final long CKR_SESSION_HANDLE_INVALID = 0x000000B3L; + public static final long CKR_SESSION_PARALLEL_NOT_SUPPORTED = 0x000000B4L; + public static final long CKR_SESSION_READ_ONLY = 0x000000B5L; + public static final long CKR_SESSION_EXISTS = 0x000000B6L; + + public static final long CKR_SESSION_READ_ONLY_EXISTS = 0x000000B7L; + public static final long CKR_SESSION_READ_WRITE_SO_EXISTS = 0x000000B8L; + + public static final long CKR_SIGNATURE_INVALID = 0x000000C0L; + public static final long CKR_SIGNATURE_LEN_RANGE = 0x000000C1L; + public static final long CKR_TEMPLATE_INCOMPLETE = 0x000000D0L; + public static final long CKR_TEMPLATE_INCONSISTENT = 0x000000D1L; + public static final long CKR_TOKEN_NOT_PRESENT = 0x000000E0L; + public static final long CKR_TOKEN_NOT_RECOGNIZED = 0x000000E1L; + public static final long CKR_TOKEN_WRITE_PROTECTED = 0x000000E2L; + public static final long CKR_UNWRAPPING_KEY_HANDLE_INVALID = 0x000000F0L; + public static final long CKR_UNWRAPPING_KEY_SIZE_RANGE = 0x000000F1L; + public static final long CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT + = 0x000000F2L; + public static final long CKR_USER_ALREADY_LOGGED_IN = 0x00000100L; + public static final long CKR_USER_NOT_LOGGED_IN = 0x00000101L; + public static final long CKR_USER_PIN_NOT_INITIALIZED = 0x00000102L; + public static final long CKR_USER_TYPE_INVALID = 0x00000103L; + + public static final long CKR_USER_ANOTHER_ALREADY_LOGGED_IN = 0x00000104L; + public static final long CKR_USER_TOO_MANY_TYPES = 0x00000105L; + + public static final long CKR_WRAPPED_KEY_INVALID = 0x00000110L; + public static final long CKR_WRAPPED_KEY_LEN_RANGE = 0x00000112L; + public static final long CKR_WRAPPING_KEY_HANDLE_INVALID = 0x00000113L; + public static final long CKR_WRAPPING_KEY_SIZE_RANGE = 0x00000114L; + public static final long CKR_WRAPPING_KEY_TYPE_INCONSISTENT = 0x00000115L; + public static final long CKR_RANDOM_SEED_NOT_SUPPORTED = 0x00000120L; + + public static final long CKR_RANDOM_NO_RNG = 0x00000121L; + + public static final long CKR_DOMAIN_PARAMS_INVALID = 0x00000130L; + + public static final long CKR_CURVE_NOT_SUPPORTED = 0x00000140L; + + public static final long CKR_BUFFER_TOO_SMALL = 0x00000150L; + public static final long CKR_SAVED_STATE_INVALID = 0x00000160L; + public static final long CKR_INFORMATION_SENSITIVE = 0x00000170L; + public static final long CKR_STATE_UNSAVEABLE = 0x00000180L; + + public static final long CKR_CRYPTOKI_NOT_INITIALIZED = 0x00000190L; + public static final long CKR_CRYPTOKI_ALREADY_INITIALIZED = 0x00000191L; + public static final long CKR_MUTEX_BAD = 0x000001A0L; + public static final long CKR_MUTEX_NOT_LOCKED = 0x000001A1L; + + public static final long CKR_NEW_PIN_MODE = 0x000001B0L; + public static final long CKR_NEXT_OTP = 0x000001B1L; + + public static final long CKR_EXCEEDED_MAX_ITERATIONS = 0x000001B5L; + public static final long CKR_FIPS_SELF_TEST_FAILED = 0x000001B6L; + public static final long CKR_LIBRARY_LOAD_FAILED = 0x000001B7L; + public static final long CKR_PIN_TOO_WEAK = 0x000001B8L; + public static final long CKR_PUBLIC_KEY_INVALID = 0x000001B9L; + public static final long CKR_FUNCTION_REJECTED = 0x00000200L; + public static final long CKR_TOKEN_RESOURCE_EXCEEDED = 0x00000201L; + public static final long CKR_OPERATION_CANCEL_FAILED = 0x00000202L; + + public static final long CKR_VENDOR_DEFINED = 0x80000000L; + + /* Uncomment when actually used + public static final long CKF_END_OF_MESSAGE = 0x00000001L; + public static final long CKF_INTERFACE_FORK_SAFE = 0x00000001L; + */ + + /* flags: bit flags that provide capabilities of the slot + * Bit Flag = Mask + */ + public static final long CKF_LIBRARY_CANT_CREATE_OS_THREADS = 0x00000001L; + public static final long CKF_OS_LOCKING_OK = 0x00000002L; + + /* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ + public static final long CKF_DONT_BLOCK = 1L; + + /* The following MGFs are defined */ + public static final long CKG_MGF1_SHA1 = 0x00000001L; + public static final long CKG_MGF1_SHA256 = 0x00000002L; + public static final long CKG_MGF1_SHA384 = 0x00000003L; + public static final long CKG_MGF1_SHA512 = 0x00000004L; + public static final long CKG_MGF1_SHA224 = 0x00000005L; + public static final long CKG_MGF1_SHA3_224 = 0x00000006L; + public static final long CKG_MGF1_SHA3_256 = 0x00000007L; + public static final long CKG_MGF1_SHA3_384 = 0x00000008L; + public static final long CKG_MGF1_SHA3_512 = 0x00000009L; + + /* The following encoding parameter sources are defined */ + public static final long CKZ_DATA_SPECIFIED = 0x00000001L; + + // the following EC Key Derivation Functions are defined + public static final long CKD_NULL = 0x00000001L; + public static final long CKD_SHA1_KDF = 0x00000002L; + + /* Uncomment when actually used + // the following X9.42 Diffie-Hellman Key Derivation Functions are defined + public static final long CKD_SHA1_KDF_ASN1 = 0x00000003L; + public static final long CKD_SHA1_KDF_CONCATENATE = 0x00000004L; + public static final long CKD_SHA224_KDF = 0x00000005L; + public static final long CKD_SHA256_KDF = 0x00000006L; + public static final long CKD_SHA384_KDF = 0x00000007L; + public static final long CKD_SHA512_KDF = 0x00000008L; + public static final long CKD_CPDIVERSIFY_KDF = 0x00000009L; + public static final long CKD_SHA3_224_KDF = 0x0000000AL; + public static final long CKD_SHA3_256_KDF = 0x0000000BL; + public static final long CKD_SHA3_384_KDF = 0x0000000CL; + public static final long CKD_SHA3_512_KDF = 0x0000000DL; + public static final long CKD_SHA1_KDF_SP800 = 0x0000000EL; + public static final long CKD_SHA224_KDF_SP800 = 0x0000000FL; + public static final long CKD_SHA256_KDF_SP800 = 0x00000010L; + public static final long CKD_SHA384_KDF_SP800 = 0x00000011L; + public static final long CKD_SHA512_KDF_SP800 = 0x00000012L; + public static final long CKD_SHA3_224_KDF_SP800 = 0x00000013L; + public static final long CKD_SHA3_256_KDF_SP800 = 0x00000014L; + public static final long CKD_SHA3_384_KDF_SP800 = 0x00000015L; + public static final long CKD_SHA3_512_KDF_SP800 = 0x00000016L; + public static final long CKD_BLAKE2B_160_KDF = 0x00000017L; + public static final long CKD_BLAKE2B_256_KDF = 0x00000018L; + public static final long CKD_BLAKE2B_384_KDF = 0x00000019L; + public static final long CKD_BLAKE2B_512_KDF = 0x0000001aL; + + public static final long CKP_PKCS5_PBKD2_HMAC_SHA1 = 0x00000001L; + public static final long CKP_PKCS5_PBKD2_HMAC_GOSTR3411 = 0x00000002L; + public static final long CKP_PKCS5_PBKD2_HMAC_SHA224 = 0x00000003L; + public static final long CKP_PKCS5_PBKD2_HMAC_SHA256 = 0x00000004L; + public static final long CKP_PKCS5_PBKD2_HMAC_SHA384 = 0x00000005L; + public static final long CKP_PKCS5_PBKD2_HMAC_SHA512 = 0x00000006L; + public static final long CKP_PKCS5_PBKD2_HMAC_SHA512_224 = 0x00000007L; + public static final long CKP_PKCS5_PBKD2_HMAC_SHA512_256 = 0x00000008L; + + public static final long CKZ_SALT_SPECIFIED = 0x00000001L; + + public static final long CK_OTP_VALUE = 0x00000000L; + public static final long CK_OTP_PIN = 0x00000001L; + public static final long CK_OTP_CHALLENGE = 0x00000002L; + public static final long CK_OTP_TIME = 0x00000003L; + public static final long CK_OTP_COUNTER = 0x00000004L; + public static final long CK_OTP_FLAGS = 0x00000005L; + public static final long CK_OTP_OUTPUT_LENGTH = 0x00000006L; + public static final long CK_OTP_OUTPUT_FORMAT = 0x00000007L; + + public static final long CKF_NEXT_OTP = 0x00000001L; + public static final long CKF_EXCLUDE_TIME = 0x00000002L; + public static final long CKF_EXCLUDE_COUNTER = 0x00000004L; + public static final long CKF_EXCLUDE_CHALLENGE = 0x00000008L; + public static final long CKF_EXCLUDE_PIN = 0x00000010L; + public static final long CKF_USER_FRIENDLY_OTP = 0x00000020L; + + public static final long CKG_NO_GENERATE = 0x00000000L; + public static final long CKG_GENERATE = 0x00000001L; + public static final long CKG_GENERATE_COUNTER = 0x00000002L; + public static final long CKG_GENERATE_RANDOM = 0x00000003L; + + public static final long CK_SP800_108_ITERATION_VARIABLE = 0x00000001L; + public static final long CK_SP800_108_OPTIONAL_COUNTER = 0x00000002L; + public static final long CK_SP800_108_DKM_LENGTH = 0x00000003L; + public static final long CK_SP800_108_BYTE_ARRAY = 0x00000004L; + public static final long CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS + = 0x00000001L; + public static final long CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS + = 0x00000002L; + + public static final long CKF_HKDF_SALT_NULL = 0x00000001L; + public static final long CKF_HKDF_SALT_DATA = 0x00000002L; + public static final long CKF_HKDF_SALT_KEY = 0x00000004L; + */ + + // private NSS attribute (for DSA and DH private keys) + public static final long CKA_NETSCAPE_DB = 0xD5A0DB00L; + + // base number of NSS private attributes + public static final long CKA_NETSCAPE_BASE /*0x80000000L + 0x4E534350L*/ + = 0xCE534350L; + + // object type for NSS trust + public static final long CKO_NETSCAPE_TRUST = 0xCE534353L; + + // base number for NSS trust attributes + public static final long CKA_NETSCAPE_TRUST_BASE = 0xCE536350L; + + // attributes for NSS trust + public static final long CKA_NETSCAPE_TRUST_SERVER_AUTH = 0xCE536358L; + public static final long CKA_NETSCAPE_TRUST_CLIENT_AUTH = 0xCE536359L; + public static final long CKA_NETSCAPE_TRUST_CODE_SIGNING = 0xCE53635AL; + public static final long CKA_NETSCAPE_TRUST_EMAIL_PROTECTION = 0xCE53635BL; + public static final long CKA_NETSCAPE_CERT_SHA1_HASH = 0xCE5363B4L; + public static final long CKA_NETSCAPE_CERT_MD5_HASH = 0xCE5363B5L; + + // trust values for each of the NSS trust attributes + public static final long CKT_NETSCAPE_TRUSTED = 0xCE534351L; + public static final long CKT_NETSCAPE_TRUSTED_DELEGATOR = 0xCE534352L; + public static final long CKT_NETSCAPE_UNTRUSTED = 0xCE534353L; + public static final long CKT_NETSCAPE_MUST_VERIFY = 0xCE534354L; + public static final long CKT_NETSCAPE_TRUST_UNKNOWN /* default */ + = 0xCE534355L; + public static final long CKT_NETSCAPE_VALID = 0xCE53435AL; + public static final long CKT_NETSCAPE_VALID_DELEGATOR = 0xCE53435BL; +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11Exception.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11Exception.java new file mode 100644 index 0000000..2be40bc --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11Exception.java @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + +import java.util.*; +import static com.sunyard.security.pkcs11.wrapper.PKCS11Constants.*; + +/** + * This is the superclass of all checked exceptions used by this package. An + * exception of this class indicates that a function call to the underlying + * PKCS#11 module returned a value not equal to CKR_OK. The application can get + * the returned value by calling getErrorCode(). A return value not equal to + * CKR_OK is the only reason for such an exception to be thrown. + * PKCS#11 defines the meaning of an error-code, which may depend on the + * context in which the error occurs. + * + * @author Karl Scheibelhofer + * @invariants + */ +public class PKCS11Exception extends Exception { + private static final long serialVersionUID = 4877072363729195L; + + /** + * The code of the error which was the reason for this exception. + */ + protected long errorCode_; + + private static final Map errorMap; + + static { + long[] errorCodes = new long[] { + CKR_OK, + CKR_CANCEL, + CKR_HOST_MEMORY, + CKR_SLOT_ID_INVALID, + CKR_GENERAL_ERROR, + CKR_FUNCTION_FAILED, + CKR_ARGUMENTS_BAD, + CKR_NO_EVENT, + CKR_NEED_TO_CREATE_THREADS, + CKR_CANT_LOCK, + CKR_ATTRIBUTE_READ_ONLY, + CKR_ATTRIBUTE_SENSITIVE, + CKR_ATTRIBUTE_TYPE_INVALID, + CKR_ATTRIBUTE_VALUE_INVALID, + CKR_ACTION_PROHIBITED, + CKR_DATA_INVALID, + CKR_DATA_LEN_RANGE, + CKR_DEVICE_ERROR, + CKR_DEVICE_MEMORY, + CKR_DEVICE_REMOVED, + CKR_ENCRYPTED_DATA_INVALID, + CKR_ENCRYPTED_DATA_LEN_RANGE, + CKR_AEAD_DECRYPT_FAILED, + CKR_FUNCTION_CANCELED, + CKR_FUNCTION_NOT_PARALLEL, + CKR_FUNCTION_NOT_SUPPORTED, + CKR_KEY_HANDLE_INVALID, + CKR_KEY_SIZE_RANGE, + CKR_KEY_TYPE_INCONSISTENT, + CKR_KEY_NOT_NEEDED, + CKR_KEY_CHANGED, + CKR_KEY_NEEDED, + CKR_KEY_INDIGESTIBLE, + CKR_KEY_FUNCTION_NOT_PERMITTED, + CKR_KEY_NOT_WRAPPABLE, + CKR_KEY_UNEXTRACTABLE, + CKR_MECHANISM_INVALID, + CKR_MECHANISM_PARAM_INVALID, + CKR_OBJECT_HANDLE_INVALID, + CKR_OPERATION_ACTIVE, + CKR_OPERATION_NOT_INITIALIZED, + CKR_PIN_INCORRECT, + CKR_PIN_INVALID, + CKR_PIN_LEN_RANGE, + CKR_PIN_EXPIRED, + CKR_PIN_LOCKED, + CKR_SESSION_CLOSED, + CKR_SESSION_COUNT, + CKR_SESSION_HANDLE_INVALID, + CKR_SESSION_PARALLEL_NOT_SUPPORTED, + CKR_SESSION_READ_ONLY, + CKR_SESSION_EXISTS, + CKR_SESSION_READ_ONLY_EXISTS, + CKR_SESSION_READ_WRITE_SO_EXISTS, + CKR_SIGNATURE_INVALID, + CKR_SIGNATURE_LEN_RANGE, + CKR_TEMPLATE_INCOMPLETE, + CKR_TEMPLATE_INCONSISTENT, + CKR_TOKEN_NOT_PRESENT, + CKR_TOKEN_NOT_RECOGNIZED, + CKR_TOKEN_WRITE_PROTECTED, + CKR_UNWRAPPING_KEY_HANDLE_INVALID, + CKR_UNWRAPPING_KEY_SIZE_RANGE, + CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, + CKR_USER_ALREADY_LOGGED_IN, + CKR_USER_NOT_LOGGED_IN, + CKR_USER_PIN_NOT_INITIALIZED, + CKR_USER_TYPE_INVALID, + CKR_USER_ANOTHER_ALREADY_LOGGED_IN, + CKR_USER_TOO_MANY_TYPES, + CKR_WRAPPED_KEY_INVALID, + CKR_WRAPPED_KEY_LEN_RANGE, + CKR_WRAPPING_KEY_HANDLE_INVALID, + CKR_WRAPPING_KEY_SIZE_RANGE, + CKR_WRAPPING_KEY_TYPE_INCONSISTENT, + CKR_RANDOM_SEED_NOT_SUPPORTED, + CKR_RANDOM_NO_RNG, + CKR_DOMAIN_PARAMS_INVALID, + CKR_CURVE_NOT_SUPPORTED, + CKR_BUFFER_TOO_SMALL, + CKR_SAVED_STATE_INVALID, + CKR_INFORMATION_SENSITIVE, + CKR_STATE_UNSAVEABLE, + CKR_CRYPTOKI_NOT_INITIALIZED, + CKR_CRYPTOKI_ALREADY_INITIALIZED, + CKR_MUTEX_BAD, + CKR_MUTEX_NOT_LOCKED, + CKR_NEW_PIN_MODE, + CKR_NEXT_OTP, + CKR_EXCEEDED_MAX_ITERATIONS, + CKR_FIPS_SELF_TEST_FAILED, + CKR_LIBRARY_LOAD_FAILED, + CKR_PIN_TOO_WEAK, + CKR_PUBLIC_KEY_INVALID, + CKR_FUNCTION_REJECTED, + CKR_TOKEN_RESOURCE_EXCEEDED, + CKR_OPERATION_CANCEL_FAILED, + CKR_VENDOR_DEFINED, + }; + String[] errorMessages = new String[] { + "CKR_OK", + "CKR_CANCEL", + "CKR_HOST_MEMORY", + "CKR_SLOT_ID_INVALID", + "CKR_GENERAL_ERROR", + "CKR_FUNCTION_FAILED", + "CKR_ARGUMENTS_BAD", + "CKR_NO_EVENT", + "CKR_NEED_TO_CREATE_THREADS", + "CKR_CANT_LOCK", + "CKR_ATTRIBUTE_READ_ONLY", + "CKR_ATTRIBUTE_SENSITIVE", + "CKR_ATTRIBUTE_TYPE_INVALID", + "CKR_ATTRIBUTE_VALUE_INVALID", + "CKR_ACTION_PROHIBITED", + "CKR_DATA_INVALID", + "CKR_DATA_LEN_RANGE", + "CKR_DEVICE_ERROR", + "CKR_DEVICE_MEMORY", + "CKR_DEVICE_REMOVED", + "CKR_ENCRYPTED_DATA_INVALID", + "CKR_ENCRYPTED_DATA_LEN_RANGE", + "CKR_AEAD_DECRYPT_FAILED", + "CKR_FUNCTION_CANCELED", + "CKR_FUNCTION_NOT_PARALLEL", + "CKR_FUNCTION_NOT_SUPPORTED", + "CKR_KEY_HANDLE_INVALID", + "CKR_KEY_SIZE_RANGE", + "CKR_KEY_TYPE_INCONSISTENT", + "CKR_KEY_NOT_NEEDED", + "CKR_KEY_CHANGED", + "CKR_KEY_NEEDED", + "CKR_KEY_INDIGESTIBLE", + "CKR_KEY_FUNCTION_NOT_PERMITTED", + "CKR_KEY_NOT_WRAPPABLE", + "CKR_KEY_UNEXTRACTABLE", + "CKR_MECHANISM_INVALID", + "CKR_MECHANISM_PARAM_INVALID", + "CKR_OBJECT_HANDLE_INVALID", + "CKR_OPERATION_ACTIVE", + "CKR_OPERATION_NOT_INITIALIZED", + "CKR_PIN_INCORRECT", + "CKR_PIN_INVALID", + "CKR_PIN_LEN_RANGE", + "CKR_PIN_EXPIRED", + "CKR_PIN_LOCKED", + "CKR_SESSION_CLOSED", + "CKR_SESSION_COUNT", + "CKR_SESSION_HANDLE_INVALID", + "CKR_SESSION_PARALLEL_NOT_SUPPORTED", + "CKR_SESSION_READ_ONLY", + "CKR_SESSION_EXISTS", + "CKR_SESSION_READ_ONLY_EXISTS", + "CKR_SESSION_READ_WRITE_SO_EXISTS", + "CKR_SIGNATURE_INVALID", + "CKR_SIGNATURE_LEN_RANGE", + "CKR_TEMPLATE_INCOMPLETE", + "CKR_TEMPLATE_INCONSISTENT", + "CKR_TOKEN_NOT_PRESENT", + "CKR_TOKEN_NOT_RECOGNIZED", + "CKR_TOKEN_WRITE_PROTECTED", + "CKR_UNWRAPPING_KEY_HANDLE_INVALID", + "CKR_UNWRAPPING_KEY_SIZE_RANGE", + "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT", + "CKR_USER_ALREADY_LOGGED_IN", + "CKR_USER_NOT_LOGGED_IN", + "CKR_USER_PIN_NOT_INITIALIZED", + "CKR_USER_TYPE_INVALID", + "CKR_USER_ANOTHER_ALREADY_LOGGED_IN", + "CKR_USER_TOO_MANY_TYPES", + "CKR_WRAPPED_KEY_INVALID", + "CKR_WRAPPED_KEY_LEN_RANGE", + "CKR_WRAPPING_KEY_HANDLE_INVALID", + "CKR_WRAPPING_KEY_SIZE_RANGE", + "CKR_WRAPPING_KEY_TYPE_INCONSISTENT", + "CKR_RANDOM_SEED_NOT_SUPPORTED", + "CKR_RANDOM_NO_RNG", + "CKR_DOMAIN_PARAMS_INVALID", + "CKR_CURVE_NOT_SUPPORTED", + "CKR_BUFFER_TOO_SMALL", + "CKR_SAVED_STATE_INVALID", + "CKR_INFORMATION_SENSITIVE", + "CKR_STATE_UNSAVEABLE", + "CKR_CRYPTOKI_NOT_INITIALIZED", + "CKR_CRYPTOKI_ALREADY_INITIALIZED", + "CKR_MUTEX_BAD", + "CKR_MUTEX_NOT_LOCKED", + "CKR_NEW_PIN_MODE", + "CKR_NEXT_OTP", + "CKR_EXCEEDED_MAX_ITERATIONS", + "CKR_FIPS_SELF_TEST_FAILED", + "CKR_LIBRARY_LOAD_FAILED", + "CKR_PIN_TOO_WEAK", + "CKR_PUBLIC_KEY_INVALID", + "CKR_FUNCTION_REJECTED", + "CKR_TOKEN_RESOURCE_EXCEEDED", + "CKR_OPERATION_CANCEL_FAILED", + "CKR_VENDOR_DEFINED", + }; + errorMap = new HashMap(); + for (int i = 0; i < errorCodes.length; i++) { + errorMap.put(Long.valueOf(errorCodes[i]), errorMessages[i]); + } + } + + + /** + * Constructor taking the error code as defined for the CKR_* constants + * in PKCS#11. + */ + public PKCS11Exception(long errorCode) { + errorCode_ = errorCode; + } + + /** + * This method gets the corresponding text error message from + * a property file. If this file is not available, it returns the error + * code as a hex-string. + * + * @return The message or the error code; e.g. "CKR_DEVICE_ERROR" or + * "0x00000030". + * @preconditions + * @postconditions (result <> null) + */ + public String getMessage() { + String message = errorMap.get(Long.valueOf(errorCode_)); + if (message == null) { + message = "0x" + Functions.toFullHexString((int)errorCode_); + } + return message; + } + + /** + * Returns the PKCS#11 error code. + * + * @return The error code; e.g. 0x00000030. + * @preconditions + * @postconditions + */ + public long getErrorCode() { + return errorCode_ ; + } + +} diff --git a/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11RuntimeException.java b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11RuntimeException.java new file mode 100644 index 0000000..34df6c6 --- /dev/null +++ b/src/main/java/com/sunyard/security/pkcs11/wrapper/PKCS11RuntimeException.java @@ -0,0 +1,109 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* Copyright (c) 2002 Graz University of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: + * + * "This product includes software developed by IAIK of Graz University of + * Technology." + * + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Graz University of Technology" and "IAIK of Graz University of + * Technology" must not be used to endorse or promote products derived from + * this software without prior written permission. + * + * 5. Products derived from this software may not be called + * "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior + * written permission of Graz University of Technology. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sunyard.security.pkcs11.wrapper; + + +/** + * This is the superclass of all runtime exception used by this library. + * For instance, Runtime exceptions occur, if an internal error in the native + * part of the wrapper occurs. + * + * @author Karl Scheibelhofer + * @invariants + */ +public class PKCS11RuntimeException extends RuntimeException { + private static final long serialVersionUID = 7889842162743590564L; + + /** + * Empty constructor. + * + * @preconditions + * @postconditions + */ + public PKCS11RuntimeException() { + super(); + } + + /** + * Constructor taking a string that describes the reason of the exception + * in more detail. + * + * @param message A descrption of the reason for this exception. + * @preconditions + * @postconditions + */ + public PKCS11RuntimeException(String message) { + super(message); + } + + /** + * Constructor taking an other exception to wrap. + * + * @param encapsulatedException The other exception the wrap into this. + * @preconditions + * @postconditions + */ + public PKCS11RuntimeException(Exception encapsulatedException) { + super(encapsulatedException); + } + + /** + * Constructor taking a message for this exception and an other exception to + * wrap. + * + * @param message The message giving details about the exception to ease + * debugging. + * @param encapsulatedException The other exception the wrap into this. + * @preconditions + * @postconditions + */ + public PKCS11RuntimeException(String message, Exception encapsulatedException) { + super(message, encapsulatedException); + } + +} diff --git a/src/main/java/com/sunyard/security/util/CurveDB.java b/src/main/java/com/sunyard/security/util/CurveDB.java new file mode 100644 index 0000000..d25b600 --- /dev/null +++ b/src/main/java/com/sunyard/security/util/CurveDB.java @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.util; + +import java.math.BigInteger; + +import java.security.spec.*; + +import java.util.*; +import java.util.regex.Pattern; + +import sun.security.util.ECUtil; + +/** + * Repository for well-known Elliptic Curve parameters. It is used by both + * the SunPKCS11 and SunJSSE code. + * + * @since 1.6 + * @author Andreas Sterbenz + */ +public class CurveDB { + private final static int P = 1; // prime curve + private final static int B = 2; // binary curve + private final static int PD = 5; // prime curve, mark as default + private final static int BD = 6; // binary curve, mark as default + + private static final Map oidMap = + new LinkedHashMap(); + private static final Map nameMap = + new HashMap(); + private static final Map lengthMap = + new HashMap(); + + private static Collection specCollection; + + public static final String SPLIT_PATTERN = ",|\\[|\\]"; + + // Used by SunECEntries + public static CollectiongetSupportedCurves() { + return specCollection; + } + + // Return a NamedCurve for the specified OID/name or null if unknown. + static NamedCurve lookup(String name) { + NamedCurve spec = oidMap.get(name); + if (spec != null) { + return spec; + } + + return nameMap.get(name); + } + + // Return EC parameters for the specified field size. If there are known + // NIST recommended parameters for the given length, they are returned. + // Otherwise, if there are multiple matches for the given size, an + // arbitrary one is returns. + // If no parameters are known, the method returns null. + // NOTE that this method returns both prime and binary curves. + static NamedCurve lookup(int length) { + return lengthMap.get(length); + } + + // Convert the given ECParameterSpec object to a NamedCurve object. + // If params does not represent a known named curve, return null. + static NamedCurve lookup(ECParameterSpec params) { + if ((params instanceof NamedCurve) || (params == null)) { + return (NamedCurve)params; + } + + // This is a hack to allow SunJSSE to work with 3rd party crypto + // providers for ECC and not just SunPKCS11. + // This can go away once we decide how to expose curve names in the + // public API. + // Note that it assumes that the 3rd party provider encodes named + // curves using the short form, not explicitly. If it did that, then + // the SunJSSE TLS ECC extensions are wrong, which could lead to + // interoperability problems. + int fieldSize = params.getCurve().getField().getFieldSize(); + for (NamedCurve namedCurve : specCollection) { + // ECParameterSpec does not define equals, so check all the + // components ourselves. + // Quick field size check first + if (namedCurve.getCurve().getField().getFieldSize() != fieldSize) { + continue; + } + if (ECUtil.equals(namedCurve, params)) { + // everything matches our named curve, return it + return namedCurve; + } + } + // no match found + return null; + } + + private static BigInteger bi(String s) { + return new BigInteger(s, 16); + } + + private static void add(String name, String soid, int type, String sfield, + String a, String b, String x, String y, String n, int h, + Pattern nameSplitPattern) { + BigInteger p = bi(sfield); + ECField field; + if ((type == P) || (type == PD)) { + field = new ECFieldFp(p); + } else if ((type == B) || (type == BD)) { + field = new ECFieldF2m(p.bitLength() - 1, p); + } else { + throw new RuntimeException("Invalid type: " + type); + } + + EllipticCurve curve = new EllipticCurve(field, bi(a), bi(b)); + ECPoint g = new ECPoint(bi(x), bi(y)); + + NamedCurve params = new NamedCurve(name, soid, curve, g, bi(n), h); + if (oidMap.put(soid, params) != null) { + throw new RuntimeException("Duplication oid: " + soid); + } + + String[] commonNames = nameSplitPattern.split(name); + for (String commonName : commonNames) { + if (nameMap.put(commonName.trim(), params) != null) { + throw new RuntimeException("Duplication name: " + commonName); + } + } + + int len = field.getFieldSize(); + if ((type == PD) || (type == BD) || (lengthMap.get(len) == null)) { + // add entry if none present for this field size or if + // the curve is marked as a default curve. + lengthMap.put(len, params); + } + } + + private static class Holder { + private static final Pattern nameSplitPattern = Pattern.compile( + SPLIT_PATTERN); + } + + // Return all the names the EC curve could be using. + static String[] getNamesByOID(String oid) { + NamedCurve nc = oidMap.get(oid); + if (nc == null) { + return new String[0]; + } + String[] list = Holder.nameSplitPattern.split(nc.getName()); + int i = 0; + do { + list[i] = list[i].trim(); + } while (++i < list.length); + return list; + } + + static { + Pattern nameSplitPattern = Holder.nameSplitPattern; + + /* SEC2 prime curves */ + add("secp112r1", "1.3.132.0.6", P, + "DB7C2ABF62E35E668076BEAD208B", + "DB7C2ABF62E35E668076BEAD2088", + "659EF8BA043916EEDE8911702B22", + "09487239995A5EE76B55F9C2F098", + "A89CE5AF8724C0A23E0E0FF77500", + "DB7C2ABF62E35E7628DFAC6561C5", + 1, nameSplitPattern); + + add("secp112r2", "1.3.132.0.7", P, + "DB7C2ABF62E35E668076BEAD208B", + "6127C24C05F38A0AAAF65C0EF02C", + "51DEF1815DB5ED74FCC34C85D709", + "4BA30AB5E892B4E1649DD0928643", + "adcd46f5882e3747def36e956e97", + "36DF0AAFD8B8D7597CA10520D04B", + 4, nameSplitPattern); + + add("secp128r1", "1.3.132.0.28", P, + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", + "E87579C11079F43DD824993C2CEE5ED3", + "161FF7528B899B2D0C28607CA52C5B86", + "CF5AC8395BAFEB13C02DA292DDED7A83", + "FFFFFFFE0000000075A30D1B9038A115", + 1, nameSplitPattern); + + add("secp128r2", "1.3.132.0.29", P, + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "D6031998D1B3BBFEBF59CC9BBFF9AEE1", + "5EEEFCA380D02919DC2C6558BB6D8A5D", + "7B6AA5D85E572983E6FB32A7CDEBC140", + "27B6916A894D3AEE7106FE805FC34B44", + "3FFFFFFF7FFFFFFFBE0024720613B5A3", + 4, nameSplitPattern); + + add("secp160k1", "1.3.132.0.9", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0000000000000000000000000000000000000000", + "0000000000000000000000000000000000000007", + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", + "938CF935318FDCED6BC28286531733C3F03C4FEE", + "0100000000000000000001B8FA16DFAB9ACA16B6B3", + 1, nameSplitPattern); + + add("secp160r1", "1.3.132.0.8", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "4A96B5688EF573284664698968C38BB913CBFC82", + "23A628553168947D59DCC912042351377AC5FB32", + "0100000000000000000001F4C8F927AED3CA752257", + 1, nameSplitPattern); + + add("secp160r2", "1.3.132.0.30", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", + "B4E134D3FB59EB8BAB57274904664D5AF50388BA", + "52DCB034293A117E1F4FF11B30F7199D3144CE6D", + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", + "0100000000000000000000351EE786A818F3A1A16B", + 1, nameSplitPattern); + + add("secp192k1", "1.3.132.0.31", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", + "000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000003", + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", + 1, nameSplitPattern); + + add("secp192r1 [NIST P-192, X9.62 prime192v1]", "1.2.840.10045.3.1.1", PD, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", + 1, nameSplitPattern); + + add("secp224k1", "1.3.132.0.32", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", + "00000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000005", + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", + "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", + 1, nameSplitPattern); + + add("secp224r1 [NIST P-224]", "1.3.132.0.33", PD, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", + "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", + 1, nameSplitPattern); + + add("secp256k1", "1.3.132.0.10", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000007", + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + 1, nameSplitPattern); + + add("secp256r1 [NIST P-256, X9.62 prime256v1]", "1.2.840.10045.3.1.7", PD, + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + 1, nameSplitPattern); + + add("secp384r1 [NIST P-384]", "1.3.132.0.34", PD, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", + "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + 1, nameSplitPattern); + + add("secp521r1 [NIST P-521]", "1.3.132.0.35", PD, + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", + "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + 1, nameSplitPattern); + + /* ANSI X9.62 prime curves */ + add("X9.62 prime192v2", "1.2.840.10045.3.1.2", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", + "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", + "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", + "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", + 1, nameSplitPattern); + + add("X9.62 prime192v3", "1.2.840.10045.3.1.3", P, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", + "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", + "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", + "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", + 1, nameSplitPattern); + + add("X9.62 prime239v1", "1.2.840.10045.3.1.4", P, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", + "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", + "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", + 1, nameSplitPattern); + + add("X9.62 prime239v2", "1.2.840.10045.3.1.5", P, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", + "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", + "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", + "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", + 1, nameSplitPattern); + + add("X9.62 prime239v3", "1.2.840.10045.3.1.6", P, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", + "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", + "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", + 1, nameSplitPattern); + + /* SEC2 binary curves */ + add("sect113r1", "1.3.132.0.4", B, + "020000000000000000000000000201", + "003088250CA6E7C7FE649CE85820F7", + "00E8BEE4D3E2260744188BE0E9C723", + "009D73616F35F4AB1407D73562C10F", + "00A52830277958EE84D1315ED31886", + "0100000000000000D9CCEC8A39E56F", + 2, nameSplitPattern); + + add("sect113r2", "1.3.132.0.5", B, + "020000000000000000000000000201", + "00689918DBEC7E5A0DD6DFC0AA55C7", + "0095E9A9EC9B297BD4BF36E059184F", + "01A57A6A7B26CA5EF52FCDB8164797", + "00B3ADC94ED1FE674C06E695BABA1D", + "010000000000000108789B2496AF93", + 2, nameSplitPattern); + + add("sect131r1", "1.3.132.0.22", B, + "080000000000000000000000000000010D", + "07A11B09A76B562144418FF3FF8C2570B8", + "0217C05610884B63B9C6C7291678F9D341", + "0081BAF91FDF9833C40F9C181343638399", + "078C6E7EA38C001F73C8134B1B4EF9E150", + "0400000000000000023123953A9464B54D", + 2, nameSplitPattern); + + add("sect131r2", "1.3.132.0.23", B, + "080000000000000000000000000000010D", + "03E5A88919D7CAFCBF415F07C2176573B2", + "04B8266A46C55657AC734CE38F018F2192", + "0356DCD8F2F95031AD652D23951BB366A8", + "0648F06D867940A5366D9E265DE9EB240F", + "0400000000000000016954A233049BA98F", + 2, nameSplitPattern); + + add("sect163k1 [NIST K-163]", "1.3.132.0.1", BD, + "0800000000000000000000000000000000000000C9", + "000000000000000000000000000000000000000001", + "000000000000000000000000000000000000000001", + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8", + "0289070FB05D38FF58321F2E800536D538CCDAA3D9", + "04000000000000000000020108A2E0CC0D99F8A5EF", + 2, nameSplitPattern); + + add("sect163r1", "1.3.132.0.2", B, + "0800000000000000000000000000000000000000C9", + "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2", + "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9", + "0369979697AB43897789566789567F787A7876A654", + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883", + "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", + 2, nameSplitPattern); + + add("sect163r2 [NIST B-163]", "1.3.132.0.15", BD, + "0800000000000000000000000000000000000000C9", + "000000000000000000000000000000000000000001", + "020A601907B8C953CA1481EB10512F78744A3205FD", + "03F0EBA16286A2D57EA0991168D4994637E8343E36", + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", + "040000000000000000000292FE77E70C12A4234C33", + 2, nameSplitPattern); + + add("sect193r1", "1.3.132.0.24", B, + "02000000000000000000000000000000000000000000008001", + "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01", + "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814", + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1", + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05", + "01000000000000000000000000C7F34A778F443ACC920EBA49", + 2, nameSplitPattern); + + add("sect193r2", "1.3.132.0.25", B, + "02000000000000000000000000000000000000000000008001", + "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B", + "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE", + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F", + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C", + "010000000000000000000000015AAB561B005413CCD4EE99D5", + 2, nameSplitPattern); + + add("sect233k1 [NIST K-233]", "1.3.132.0.26", BD, + "020000000000000000000000000000000000000004000000000000000001", + "000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000001", + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126", + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", + "008000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", + 4, nameSplitPattern); + + add("sect233r1 [NIST B-233]", "1.3.132.0.27", B, + "020000000000000000000000000000000000000004000000000000000001", + "000000000000000000000000000000000000000000000000000000000001", + "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B", + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", + "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", + 2, nameSplitPattern); + + add("sect239k1", "1.3.132.0.3", B, + "800000000000000000004000000000000000000000000000000000000001", + "000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000001", + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC", + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA", + "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", + 4, nameSplitPattern); + + add("sect283k1 [NIST K-283]", "1.3.132.0.16", BD, + "0800000000000000000000000000000000000000000000000000000000000000000010A1", + "000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000001", + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836", + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", + 4, nameSplitPattern); + + add("sect283r1 [NIST B-283]", "1.3.132.0.17", B, + "0800000000000000000000000000000000000000000000000000000000000000000010A1", + "000000000000000000000000000000000000000000000000000000000000000000000001", + "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", + 2, nameSplitPattern); + + add("sect409k1 [NIST K-409]", "1.3.132.0.36", BD, + "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746", + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", + "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", + 4, nameSplitPattern); + + add("sect409r1 [NIST B-409]", "1.3.132.0.37", B, + "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7", + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", + "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", + 2, nameSplitPattern); + + add("sect571k1 [NIST K-571]", "1.3.132.0.38", BD, + "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972", + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", + "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", + 4, nameSplitPattern); + + add("sect571r1 [NIST B-571]", "1.3.132.0.39", B, + "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19", + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", + 2, nameSplitPattern); + + /* ANSI X9.62 binary curves */ + add("X9.62 c2tnb191v1", "1.2.840.10045.3.0.5", B, + "800000000000000000000000000000000000000000000201", + "2866537B676752636A68F56554E12640276B649EF7526267", + "2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", + "36B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D", + "765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB", + "40000000000000000000000004A20E90C39067C893BBB9A5", + 2, nameSplitPattern); + + add("X9.62 c2tnb191v2", "1.2.840.10045.3.0.6", B, + "800000000000000000000000000000000000000000000201", + "401028774D7777C7B7666D1366EA432071274F89FF01E718", + "0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", + "3809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10", + "17434386626D14F3DBF01760D9213A3E1CF37AEC437D668A", + "20000000000000000000000050508CB89F652824E06B8173", + 4, nameSplitPattern); + + add("X9.62 c2tnb191v3", "1.2.840.10045.3.0.7", B, + "800000000000000000000000000000000000000000000201", + "6C01074756099122221056911C77D77E77A777E7E7E77FCB", + "71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", + "375D4CE24FDE434489DE8746E71786015009E66E38A926DD", + "545A39176196575D985999366E6AD34CE0A77CD7127B06BE", + "155555555555555555555555610C0B196812BFB6288A3EA3", + 6, nameSplitPattern); + + add("X9.62 c2tnb239v1", "1.2.840.10045.3.0.11", B, + "800000000000000000000000000000000000000000000000001000000001", + "32010857077C5431123A46B808906756F543423E8D27877578125778AC76", + "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", + "57927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D", + "61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305", + "2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", + 4, nameSplitPattern); + + add("X9.62 c2tnb239v2", "1.2.840.10045.3.0.12", B, + "800000000000000000000000000000000000000000000000001000000001", + "4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", + "5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", + "28F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205", + "5667334C45AFF3B5A03BAD9DD75E2C71A99362567D5453F7FA6E227EC833", + "1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", + 6, nameSplitPattern); + + add("X9.62 c2tnb239v3", "1.2.840.10045.3.0.13", B, + "800000000000000000000000000000000000000000000000001000000001", + "01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", + "6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", + "70F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92", + "2E5A0EAF6E5E1305B9004DCE5C0ED7FE59A35608F33837C816D80B79F461", + "0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", + 0xA, nameSplitPattern); + + add("X9.62 c2tnb359v1", "1.2.840.10045.3.0.18", B, + "800000000000000000000000000000000000000000000000000000000000000000000000100000000000000001", + "5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", + "2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", + "3C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097", + "53D7E08529547048121E9C95F3791DD804963948F34FAE7BF44EA82365DC7868FE57E4AE2DE211305A407104BD", + "01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", + 0x4C, nameSplitPattern); + + add("X9.62 c2tnb431r1", "1.2.840.10045.3.0.20", B, + "800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001", + "1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", + "10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", + "120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7", + "20D0AF8903A96F8D5FA2C255745D3C451B302C9346D9B7E485E7BCE41F6B591F3E8F6ADDCBB0BC4C2F947A7DE1A89B625D6A598B3760", + "0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", + 0x2760, nameSplitPattern); + + /* ANSI X9.62 binary curves from the 1998 standard but forbidden + * in the 2005 version of the standard. + * We don't register them but leave them here for the time being in + * case we need to support them after all. + */ +/* + add("X9.62 c2pnb163v1", "1.2.840.10045.3.0.1", B, + "080000000000000000000000000000000000000107", + "072546B5435234A422E0789675F432C89435DE5242", + "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", + "07AF69989546103D79329FCC3D74880F33BBE803CB", + "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F", + "0400000000000000000001E60FC8821CC74DAEAFC1", + 2, nameSplitPattern); + + add("X9.62 c2pnb163v2", "1.2.840.10045.3.0.2", B, + "080000000000000000000000000000000000000107", + "0108B39E77C4B108BED981ED0E890E117C511CF072", + "0667ACEB38AF4E488C407433FFAE4F1C811638DF20", + "0024266E4EB5106D0A964D92C4860E2671DB9B6CC5", + "079F684DDF6684C5CD258B3890021B2386DFD19FC5", + "03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", + 2, nameSplitPattern); + + add("X9.62 c2pnb163v3", "1.2.840.10045.3.0.3", B, + "080000000000000000000000000000000000000107", + "07A526C63D3E25A256A007699F5447E32AE456B50E", + "03F7061798EB99E238FD6F1BF95B48FEEB4854252B", + "02F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB", + "05B935590C155E17EA48EB3FF3718B893DF59A05D0", + "03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", + 2, nameSplitPattern); + + add("X9.62 c2pnb176w1", "1.2.840.10045.3.0.4", B, + "0100000000000000000000000000000000080000000007", + "E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", + "5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", + "8D16C2866798B600F9F08BB4A8E860F3298CE04A5798", + "6FA4539C2DADDDD6BAB5167D61B436E1D92BB16A562C", + "00010092537397ECA4F6145799D62B0A19CE06FE26AD", + 0xFF6E, nameSplitPattern); + + add("X9.62 c2pnb208w1", "1.2.840.10045.3.0.10", B, + "010000000000000000000000000000000800000000000000000007", + "0000000000000000000000000000000000000000000000000000", + "C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", + "89FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A", + "0F55B51A06E78E9AC38A035FF520D8B01781BEB1A6BB08617DE3", + "000101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", + 0xFE48, nameSplitPattern); + + add("X9.62 c2pnb272w1", "1.2.840.10045.3.0.16", B, + "010000000000000000000000000000000000000000000000000000010000000000000B", + "91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", + "7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", + "6108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D", + "10C7695716851EEF6BA7F6872E6142FBD241B830FF5EFCACECCAB05E02005DDE9D23", + "000100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", + 0xFF06, nameSplitPattern); + + add("X9.62 c2pnb304w1", "1.2.840.10045.3.0.17", B, + "010000000000000000000000000000000000000000000000000000000000000000000000000807", + "FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", + "BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", + "197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614", + "E19FBEB76E0DA171517ECF401B50289BF014103288527A9B416A105E80260B549FDC1B92C03B", + "000101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", + 0xFE2E, nameSplitPattern); + + add("X9.62 c2pnb368w1", "1.2.840.10045.3.0.19", B, + "0100000000000000000000000000000000000000000000000000000000000000000000002000000000000000000007", + "E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", + "FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", + "1085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F", + "7B3EB1BDDCBA62D5D8B2059B525797FC73822C59059C623A45FF3843CEE8F87CD1855ADAA81E2A0750B80FDA2310", + "00010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", + 0xFF70, nameSplitPattern); +*/ + + /* + * Brainpool curves (RFC 5639) + * (Twisted curves are not included) + */ + + add("brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1", P, + "E95E4A5F737059DC60DFC7AD95B3D8139515620F", + "340E7BE2A280EB74E2BE61BADA745D97E8F7C300", + "1E589A8595423412134FAA2DBDEC95C8D8675E58", + "BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", + "1667CB477A1A8EC338F94741669C976316DA6321", + "E95E4A5F737059DC60DF5991D45029409E60FC09", + 1, nameSplitPattern); + + add("brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", P, + "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", + "6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", + "469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", + "C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6", + "14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", + "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", + 1, nameSplitPattern); + + add("brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", P, + "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", + "68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", + "2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", + "0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D", + "58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", + "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", + 1, nameSplitPattern); + + add("brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", P, + "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", + "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", + "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", + "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", + "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", + "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", + 1, nameSplitPattern); + + add("brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", P, + "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", + "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", + "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", + "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", + "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", + "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", + 1, nameSplitPattern); + + add("brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", P, + "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", + "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", + "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", + "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", + "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", + "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", + 1, nameSplitPattern); + + add("brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", P, + "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", + "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", + "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", + "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", + "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", + "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", + 1, nameSplitPattern); + + specCollection = Collections.unmodifiableCollection(oidMap.values()); + } +} diff --git a/src/main/java/com/sunyard/security/util/ECParameters.java b/src/main/java/com/sunyard/security/util/ECParameters.java new file mode 100644 index 0000000..9ad5077 --- /dev/null +++ b/src/main/java/com/sunyard/security/util/ECParameters.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.util; + +import sun.security.util.DerValue; +import sun.security.util.ECKeySizeParameterSpec; +import sun.security.util.ObjectIdentifier; + +import java.io.IOException; + +import java.security.*; +import java.security.spec.*; + +/** + * This class implements encoding and decoding of Elliptic Curve parameters + * as specified in RFC 3279. + * + * However, only named curves are currently supported. + * + * ASN.1 from RFC 3279 follows. Note that X9.62 (2005) has added some additional + * options. + * + *
+ *    EcpkParameters ::= CHOICE {
+ *      ecParameters  ECParameters,
+ *      namedCurve    OBJECT IDENTIFIER,
+ *      implicitlyCA  NULL }
+ *
+ *    ECParameters ::= SEQUENCE {
+ *       version   ECPVer,          -- version is always 1
+ *       fieldID   FieldID,         -- identifies the finite field over
+ *                                  -- which the curve is defined
+ *       curve     Curve,           -- coefficients a and b of the
+ *                                  -- elliptic curve
+ *       base      ECPoint,         -- specifies the base point P
+ *                                  -- on the elliptic curve
+ *       order     INTEGER,         -- the order n of the base point
+ *       cofactor  INTEGER OPTIONAL -- The integer h = #E(Fq)/n
+ *       }
+ *
+ *    ECPVer ::= INTEGER {ecpVer1(1)}
+ *
+ *    Curve ::= SEQUENCE {
+ *       a         FieldElement,
+ *       b         FieldElement,
+ *       seed      BIT STRING OPTIONAL }
+ *
+ *    FieldElement ::= OCTET STRING
+ *
+ *    ECPoint ::= OCTET STRING
+ * 
+ * + * @since 1.6 + * @author Andreas Sterbenz + */ +public final class ECParameters extends AlgorithmParametersSpi { + + // used by ECPublicKeyImpl and ECPrivateKeyImpl + public static AlgorithmParameters getAlgorithmParameters(ECParameterSpec spec) + throws InvalidKeyException { + try { + AlgorithmParameters params = + AlgorithmParameters.getInstance("EC", "SunEC"); + params.init(spec); + return params; + } catch (GeneralSecurityException e) { + throw new InvalidKeyException("EC parameters error", e); + } + } + + /* + * The parameters these AlgorithmParameters object represents. + * Currently, it is always an instance of NamedCurve. + */ + private NamedCurve namedCurve; + + // A public constructor is required by AlgorithmParameters class. + public ECParameters() { + // empty + } + + // AlgorithmParameterSpi methods + + protected void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException { + + if (paramSpec == null) { + throw new InvalidParameterSpecException + ("paramSpec must not be null"); + } + + if (paramSpec instanceof NamedCurve) { + namedCurve = (NamedCurve)paramSpec; + return; + } + + if (paramSpec instanceof ECParameterSpec) { + namedCurve = CurveDB.lookup((ECParameterSpec)paramSpec); + } else if (paramSpec instanceof ECGenParameterSpec) { + String name = ((ECGenParameterSpec)paramSpec).getName(); + namedCurve = CurveDB.lookup(name); + } else if (paramSpec instanceof ECKeySizeParameterSpec) { + int keySize = ((ECKeySizeParameterSpec)paramSpec).getKeySize(); + namedCurve = CurveDB.lookup(keySize); + } else { + throw new InvalidParameterSpecException + ("Only ECParameterSpec and ECGenParameterSpec supported"); + } + + if (namedCurve == null) { + throw new InvalidParameterSpecException( + "Not a supported curve: " + paramSpec); + } + } + + protected void engineInit(byte[] params) throws IOException { + DerValue encodedParams = new DerValue(params); + if (encodedParams.tag == DerValue.tag_ObjectId) { + ObjectIdentifier oid = encodedParams.getOID(); + NamedCurve spec = CurveDB.lookup(oid.toString()); + if (spec == null) { + throw new IOException("Unknown named curve: " + oid); + } + + namedCurve = spec; + return; + } + + throw new IOException("Only named ECParameters supported"); + + // The code below is incomplete. + // It is left as a starting point for a complete parsing implementation. + +/* + if (encodedParams.tag != DerValue.tag_Sequence) { + throw new IOException("Unsupported EC parameters, tag: " + + encodedParams.tag); + } + + encodedParams.data.reset(); + + DerInputStream in = encodedParams.data; + + int version = in.getInteger(); + if (version != 1) { + throw new IOException("Unsupported EC parameters version: " + + version); + } + ECField field = parseField(in); + EllipticCurve curve = parseCurve(in, field); + ECPoint point = parsePoint(in, curve); + + BigInteger order = in.getBigInteger(); + int cofactor = 0; + + if (in.available() != 0) { + cofactor = in.getInteger(); + } + + // XXX HashAlgorithm optional + + if (encodedParams.data.available() != 0) { + throw new IOException("encoded params have " + + encodedParams.data.available() + + " extra bytes"); + } + + return new ECParameterSpec(curve, point, order, cofactor); +*/ + } + + protected void engineInit(byte[] params, String decodingMethod) + throws IOException { + engineInit(params); + } + + protected T + engineGetParameterSpec(Class spec) + throws InvalidParameterSpecException { + + if (spec.isAssignableFrom(ECParameterSpec.class)) { + return spec.cast(namedCurve); + } + + if (spec.isAssignableFrom(ECGenParameterSpec.class)) { + // Ensure the name is the Object ID + String name = namedCurve.getObjectId(); + return spec.cast(new ECGenParameterSpec(name)); + } + + if (spec.isAssignableFrom(ECKeySizeParameterSpec.class)) { + int keySize = namedCurve.getCurve().getField().getFieldSize(); + return spec.cast(new ECKeySizeParameterSpec(keySize)); + } + + throw new InvalidParameterSpecException( + "Only ECParameterSpec and ECGenParameterSpec supported"); + } + + protected byte[] engineGetEncoded() throws IOException { + return namedCurve.getEncoded(); + } + + protected byte[] engineGetEncoded(String encodingMethod) + throws IOException { + return engineGetEncoded(); + } + + protected String engineToString() { + if (namedCurve == null) { + return "Not initialized"; + } + + return namedCurve.toString(); + } +} + diff --git a/src/main/java/com/sunyard/security/util/GCMParameters.java b/src/main/java/com/sunyard/security/util/GCMParameters.java new file mode 100644 index 0000000..8e21d86 --- /dev/null +++ b/src/main/java/com/sunyard/security/util/GCMParameters.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.util; + +import java.io.IOException; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import javax.crypto.spec.GCMParameterSpec; +import sun.misc.HexDumpEncoder; +import sun.security.util.*; + +/** + * This class implements the parameter set used with + * GCM encryption, which is defined in RFC 5084 as follows: + * + *
+ *    GCMParameters ::= SEQUENCE {
+ *      aes-iv      OCTET STRING, -- recommended size is 12 octets
+ *      aes-tLen    AES-GCM-ICVlen DEFAULT 12 }
+ *
+ *    AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
+ *
+ * 
+ * + * @since 13 + */ +public final class GCMParameters extends AlgorithmParametersSpi { + + // the iv + private byte[] iv; + // the tag length in bytes + private int tLen; + + public GCMParameters() {} + + protected void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException { + + if (!(paramSpec instanceof GCMParameterSpec)) { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + GCMParameterSpec gps = (GCMParameterSpec) paramSpec; + // need to convert from bits to bytes for ASN.1 encoding + this.tLen = gps.getTLen()/8; + if (this.tLen < 12 || this.tLen > 16 ) { + throw new InvalidParameterSpecException + ("GCM parameter parsing error: unsupported tag len: " + + this.tLen); + } + this.iv = gps.getIV(); + } + + protected void engineInit(byte[] encoded) throws IOException { + DerValue val = new DerValue(encoded); + // check if IV or params + if (val.tag == DerValue.tag_Sequence) { + byte[] iv = val.data.getOctetString(); + int tLen; + if (val.data.available() != 0) { + tLen = val.data.getInteger(); + if (tLen < 12 || tLen > 16 ) { + throw new IOException + ("GCM parameter parsing error: unsupported tag len: " + + tLen); + } + if (val.data.available() != 0) { + throw new IOException + ("GCM parameter parsing error: extra data"); + } + } else { + tLen = 12; + } + this.iv = iv.clone(); + this.tLen = tLen; + } else { + throw new IOException("GCM parameter parsing error: no SEQ tag"); + } + } + + protected void engineInit(byte[] encoded, String decodingMethod) + throws IOException { + engineInit(encoded); + } + + protected + T engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException { + + if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) { + return paramSpec.cast(new GCMParameterSpec(tLen * 8, iv)); + } else { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + } + + protected byte[] engineGetEncoded() throws IOException { + DerOutputStream out = new DerOutputStream(); + DerOutputStream bytes = new DerOutputStream(); + + bytes.putOctetString(iv); + // Only put non-default values + if (tLen != 12) { + bytes.putInteger(tLen); + } + out.write(DerValue.tag_Sequence, bytes); + return out.toByteArray(); + } + + protected byte[] engineGetEncoded(String encodingMethod) + throws IOException { + return engineGetEncoded(); + } + + /* + * Returns a formatted string describing the parameters. + */ + protected String engineToString() { + String LINE_SEP = System.lineSeparator(); + HexDumpEncoder encoder = new HexDumpEncoder(); + StringBuilder sb + = new StringBuilder(LINE_SEP + " iv:" + LINE_SEP + "[" + + encoder.encodeBuffer(iv) + "]"); + + sb.append(LINE_SEP + "tLen(bits):" + LINE_SEP + tLen*8 + LINE_SEP); + return sb.toString(); + } +} diff --git a/src/main/java/com/sunyard/security/util/NamedCurve.java b/src/main/java/com/sunyard/security/util/NamedCurve.java new file mode 100644 index 0000000..f4549ec --- /dev/null +++ b/src/main/java/com/sunyard/security/util/NamedCurve.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sunyard.security.util; + +import sun.security.util.DerOutputStream; +import sun.security.util.ObjectIdentifier; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.spec.*; + + +/** + * Contains Elliptic Curve parameters. + * + * @since 1.6 + * @author Andreas Sterbenz + */ +public final class NamedCurve extends ECParameterSpec { + + // friendly name for toString() output + private final String name; + + // well known OID + private final String oid; + + // encoded form (as NamedCurve identified via OID) + private final byte[] encoded; + + NamedCurve(String name, String oid, EllipticCurve curve, + ECPoint g, BigInteger n, int h) { + super(curve, g, n, h); + this.name = name; + this.oid = oid; + + DerOutputStream out = new DerOutputStream(); + + try { + out.putOID(new ObjectIdentifier(oid)); + } catch (IOException e) { + throw new RuntimeException("Internal error", e); + } + + encoded = out.toByteArray(); + } + + public String getName() { + return name; + } + + public byte[] getEncoded() { + return encoded.clone(); + } + + public String getObjectId() { + return oid; + } + + public String toString() { + return name + " (" + oid + ")"; + } +}