From 24e921597b26b5b98bcadacd021953a2d45b75ef Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Mon, 17 Oct 2022 13:25:41 -0500 Subject: [PATCH 01/18] Force line feeds to LF. --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..fcadb2cf979 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text eol=lf From d755e1456fe682db66ee74c4162a3c77be16bf3d Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Mon, 17 Oct 2022 13:35:07 -0500 Subject: [PATCH 02/18] Untext everything. --- .gitattributes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index fcadb2cf979..409e8b248bd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -* text eol=lf +* -text +* binary From 0e0a80cdeed42237b92dbad3f66eb49c1033ef1c Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Tue, 18 Oct 2022 14:44:31 -0500 Subject: [PATCH 03/18] Had a whitespace between platforms. I think this was causing a parsing error. --- jdk/test/ProblemList.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 93fdaed190f..897f0440ced 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -255,8 +255,8 @@ sun/security/tools/keytool/standard.sh solaris-all # jdk_tools # Tests take too long, on sparcs see 7143279 -tools/pack200/CommandLineTests.java solaris-all, macosx-all -tools/pack200/Pack200Test.java solaris-all, macosx-all +tools/pack200/CommandLineTests.java solaris-all,macosx-all +tools/pack200/Pack200Test.java solaris-all,macosx-all # 8007410 tools/launcher/FXLauncherTest.java linux-all From e0b32f678cccdc17aa34d6c9837457628f6aa500 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Fri, 5 Jan 2024 20:41:36 -0600 Subject: [PATCH 04/18] Give it 11 years. --- .../GenerateCurrencyData.java | 766 +++++++++--------- 1 file changed, 383 insertions(+), 383 deletions(-) diff --git a/jdk/make/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java b/jdk/make/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java index d424bc1494b..cc47a415d80 100644 --- a/jdk/make/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java +++ b/jdk/make/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java @@ -1,383 +1,383 @@ -/* - * Copyright (c) 2001, 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 build.tools.generatecurrencydata; - -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.DataOutputStream; -import java.io.FileOutputStream; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Properties; -import java.util.TimeZone; - -/** - * Reads currency data in properties format from the file specified in the - * command line and generates a binary data file as specified in the command line. - * - * Output of this tool is a binary file that contains the data in - * the following order: - * - * - magic number (int): always 0x43757244 ('CurD') - * - formatVersion (int) - * - dataVersion (int) - * - mainTable (int[26*26]) - * - specialCaseCount (int) - * - specialCaseCutOverTimes (long[specialCaseCount]) - * - specialCaseOldCurrencies (String[specialCaseCount]) - * - specialCaseNewCurrencies (String[specialCaseCount]) - * - specialCaseOldCurrenciesDefaultFractionDigits (int[specialCaseCount]) - * - specialCaseNewCurrenciesDefaultFractionDigits (int[specialCaseCount]) - * - specialCaseOldCurrenciesNumericCode (int[specialCaseCount]) - * - specialCaseNewCurrenciesNumericCode (int[specialCaseCount]) - * - otherCurrenciesCount (int) - * - otherCurrencies (String) - * - otherCurrenciesDefaultFractionDigits (int[otherCurrenciesCount]) - * - otherCurrenciesNumericCode (int[otherCurrenciesCount]) - * - * See CurrencyData.properties for the input format description and - * Currency.java for the format descriptions of the generated tables. - */ -public class GenerateCurrencyData { - - private static DataOutputStream out; - - // input data: currency data obtained from properties on input stream - private static Properties currencyData; - private static String formatVersion; - private static String dataVersion; - private static String validCurrencyCodes; - - // handy constants - must match definitions in java.util.Currency - // magic number - private static final int MAGIC_NUMBER = 0x43757244; - // number of characters from A to Z - private static final int A_TO_Z = ('Z' - 'A') + 1; - // entry for invalid country codes - private static final int INVALID_COUNTRY_ENTRY = 0x0000007F; - // entry for countries without currency - private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200; - // mask for simple case country entries - private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000; - // mask for simple case country entry final character - private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F; - // mask for simple case country entry default currency digits - private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0; - // shift count for simple case country entry default currency digits - private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5; - // maximum number for simple case country entry default currency digits - private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9; - // mask for special case country entries - private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200; - // mask for special case country index - private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F; - // delta from entry index component in main table to index into special case tables - private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1; - // mask for distinguishing simple and special case countries - private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK; - // mask for the numeric code of the currency - private static final int NUMERIC_CODE_MASK = 0x000FFC00; - // shift count for the numeric code of the currency - private static final int NUMERIC_CODE_SHIFT = 10; - - // generated data - private static int[] mainTable = new int[A_TO_Z * A_TO_Z]; - - private static final int maxSpecialCases = 30; - private static int specialCaseCount = 0; - private static long[] specialCaseCutOverTimes = new long[maxSpecialCases]; - private static String[] specialCaseOldCurrencies = new String[maxSpecialCases]; - private static String[] specialCaseNewCurrencies = new String[maxSpecialCases]; - private static int[] specialCaseOldCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; - private static int[] specialCaseNewCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; - private static int[] specialCaseOldCurrenciesNumericCode = new int[maxSpecialCases]; - private static int[] specialCaseNewCurrenciesNumericCode = new int[maxSpecialCases]; - - private static final int maxOtherCurrencies = 128; - private static int otherCurrenciesCount = 0; - private static StringBuffer otherCurrencies = new StringBuffer(); - private static int[] otherCurrenciesDefaultFractionDigits = new int[maxOtherCurrencies]; - private static int[] otherCurrenciesNumericCode= new int[maxOtherCurrencies]; - - // date format for parsing cut-over times - private static SimpleDateFormat format; - - // Minor Units - private static String[] currenciesWithDefinedMinorUnitDecimals = - new String[SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS + 1]; - private static String currenciesWithMinorUnitsUndefined; - - public static void main(String[] args) { - - // Look for "-o outputfilename" option - if ( args.length == 2 && args[0].equals("-o") ) { - try { - out = new DataOutputStream(new FileOutputStream(args[1])); - } catch ( FileNotFoundException e ) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(System.err); - System.exit(1); - } - } else { - System.err.println("Error: Illegal arg count"); - System.exit(1); - } - - format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - format.setLenient(false); - - try { - readInput(); - buildMainAndSpecialCaseTables(); - buildOtherTables(); - writeOutput(); - out.flush(); - out.close(); - } catch (Exception e) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(System.err); - System.exit(1); - } - } - - private static void readInput() throws IOException { - currencyData = new Properties(); - currencyData.load(System.in); - - // initialize other lookup strings - formatVersion = (String) currencyData.get("formatVersion"); - dataVersion = (String) currencyData.get("dataVersion"); - validCurrencyCodes = (String) currencyData.get("all"); - for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { - currenciesWithDefinedMinorUnitDecimals[i] - = (String) currencyData.get("minor"+i); - } - currenciesWithMinorUnitsUndefined = (String) currencyData.get("minorUndefined"); - if (formatVersion == null || - dataVersion == null || - validCurrencyCodes == null || - currenciesWithMinorUnitsUndefined == null) { - throw new NullPointerException("not all required data is defined in input"); - } - } - - private static void buildMainAndSpecialCaseTables() throws Exception { - for (int first = 0; first < A_TO_Z; first++) { - for (int second = 0; second < A_TO_Z; second++) { - char firstChar = (char) ('A' + first); - char secondChar = (char) ('A' + second); - String countryCode = (new StringBuffer()).append(firstChar).append(secondChar).toString(); - String currencyInfo = (String) currencyData.get(countryCode); - int tableEntry = 0; - if (currencyInfo == null) { - // no entry -> must be invalid ISO 3166 country code - tableEntry = INVALID_COUNTRY_ENTRY; - } else { - int length = currencyInfo.length(); - if (length == 0) { - // special case: country without currency - tableEntry = COUNTRY_WITHOUT_CURRENCY_ENTRY; - } else if (length == 3) { - // valid currency - if (currencyInfo.charAt(0) == firstChar && currencyInfo.charAt(1) == secondChar) { - checkCurrencyCode(currencyInfo); - int digits = getDefaultFractionDigits(currencyInfo); - if (digits < 0 || digits > SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS) { - throw new RuntimeException("fraction digits out of range for " + currencyInfo); - } - int numericCode= getNumericCode(currencyInfo); - if (numericCode < 0 || numericCode >= 1000 ) { - throw new RuntimeException("numeric code out of range for " + currencyInfo); - } - tableEntry = SIMPLE_CASE_COUNTRY_MASK - | (currencyInfo.charAt(2) - 'A') - | (digits << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) - | (numericCode << NUMERIC_CODE_SHIFT); - } else { - tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); - } - } else { - tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); - } - } - mainTable[first * A_TO_Z + second] = tableEntry; - } - } - } - - private static int getDefaultFractionDigits(String currencyCode) { - for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { - if (currenciesWithDefinedMinorUnitDecimals[i] != null && - currenciesWithDefinedMinorUnitDecimals[i].indexOf(currencyCode) != -1) { - return i; - } - } - - if (currenciesWithMinorUnitsUndefined.indexOf(currencyCode) != -1) { - return -1; - } else { - return 2; - } - } - - private static int getNumericCode(String currencyCode) { - int index = validCurrencyCodes.indexOf(currencyCode); - String numericCode = validCurrencyCodes.substring(index + 3, index + 6); - return Integer.parseInt(numericCode); - } - - static HashMap specialCaseMap = new HashMap<>(); - - private static int makeSpecialCaseEntry(String currencyInfo) throws Exception { - Integer oldEntry = specialCaseMap.get(currencyInfo); - if (oldEntry != null) { - return oldEntry.intValue(); - } - if (specialCaseCount == maxSpecialCases) { - throw new RuntimeException("too many special cases"); - } - if (currencyInfo.length() == 3) { - checkCurrencyCode(currencyInfo); - specialCaseCutOverTimes[specialCaseCount] = Long.MAX_VALUE; - specialCaseOldCurrencies[specialCaseCount] = currencyInfo; - specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(currencyInfo); - specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(currencyInfo); - specialCaseNewCurrencies[specialCaseCount] = null; - specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = 0; - specialCaseNewCurrenciesNumericCode[specialCaseCount] = 0; - } else { - int length = currencyInfo.length(); - if (currencyInfo.charAt(3) != ';' || - currencyInfo.charAt(length - 4) != ';') { - throw new RuntimeException("invalid currency info: " + currencyInfo); - } - String oldCurrency = currencyInfo.substring(0, 3); - String newCurrency = currencyInfo.substring(length - 3, length); - checkCurrencyCode(oldCurrency); - checkCurrencyCode(newCurrency); - String timeString = currencyInfo.substring(4, length - 4); - long time = format.parse(timeString).getTime(); - if (Math.abs(time - System.currentTimeMillis()) > ((long) 10) * 365 * 24 * 60 * 60 * 1000) { - throw new RuntimeException("time is more than 10 years from present: " + time); - } - specialCaseCutOverTimes[specialCaseCount] = time; - specialCaseOldCurrencies[specialCaseCount] = oldCurrency; - specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(oldCurrency); - specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(oldCurrency); - specialCaseNewCurrencies[specialCaseCount] = newCurrency; - specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(newCurrency); - specialCaseNewCurrenciesNumericCode[specialCaseCount] = getNumericCode(newCurrency); - } - specialCaseMap.put(currencyInfo, new Integer(specialCaseCount)); - return specialCaseCount++; - } - - private static void buildOtherTables() { - if (validCurrencyCodes.length() % 7 != 6) { - throw new RuntimeException("\"all\" entry has incorrect size"); - } - for (int i = 0; i < (validCurrencyCodes.length() + 1) / 7; i++) { - if (i > 0 && validCurrencyCodes.charAt(i * 7 - 1) != '-') { - throw new RuntimeException("incorrect separator in \"all\" entry"); - } - String currencyCode = validCurrencyCodes.substring(i * 7, i * 7 + 3); - int numericCode = Integer.parseInt( - validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); - checkCurrencyCode(currencyCode); - int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; - if (tableEntry == INVALID_COUNTRY_ENTRY || - (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || - (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { - if (otherCurrenciesCount == maxOtherCurrencies) { - throw new RuntimeException("too many other currencies"); - } - if (otherCurrencies.length() > 0) { - otherCurrencies.append('-'); - } - otherCurrencies.append(currencyCode); - otherCurrenciesDefaultFractionDigits[otherCurrenciesCount] = getDefaultFractionDigits(currencyCode); - otherCurrenciesNumericCode[otherCurrenciesCount] = getNumericCode(currencyCode); - otherCurrenciesCount++; - } - } - } - - private static void checkCurrencyCode(String currencyCode) { - if (currencyCode.length() != 3) { - throw new RuntimeException("illegal length for currency code: " + currencyCode); - } - for (int i = 0; i < 3; i++) { - char aChar = currencyCode.charAt(i); - if ((aChar < 'A' || aChar > 'Z') && !currencyCode.equals("XB5")) { - throw new RuntimeException("currency code contains illegal character: " + currencyCode); - } - } - if (validCurrencyCodes.indexOf(currencyCode) == -1) { - throw new RuntimeException("currency code not listed as valid: " + currencyCode); - } - } - - private static void writeOutput() throws IOException { - out.writeInt(MAGIC_NUMBER); - out.writeInt(Integer.parseInt(formatVersion)); - out.writeInt(Integer.parseInt(dataVersion)); - writeIntArray(mainTable, mainTable.length); - out.writeInt(specialCaseCount); - writeLongArray(specialCaseCutOverTimes, specialCaseCount); - writeStringArray(specialCaseOldCurrencies, specialCaseCount); - writeStringArray(specialCaseNewCurrencies, specialCaseCount); - writeIntArray(specialCaseOldCurrenciesDefaultFractionDigits, specialCaseCount); - writeIntArray(specialCaseNewCurrenciesDefaultFractionDigits, specialCaseCount); - writeIntArray(specialCaseOldCurrenciesNumericCode, specialCaseCount); - writeIntArray(specialCaseNewCurrenciesNumericCode, specialCaseCount); - out.writeInt(otherCurrenciesCount); - out.writeUTF(otherCurrencies.toString()); - writeIntArray(otherCurrenciesDefaultFractionDigits, otherCurrenciesCount); - writeIntArray(otherCurrenciesNumericCode, otherCurrenciesCount); - } - - private static void writeIntArray(int[] ia, int count) throws IOException { - for (int i = 0; i < count; i ++) { - out.writeInt(ia[i]); - } - } - - private static void writeLongArray(long[] la, int count) throws IOException { - for (int i = 0; i < count; i ++) { - out.writeLong(la[i]); - } - } - - private static void writeStringArray(String[] sa, int count) throws IOException { - for (int i = 0; i < count; i ++) { - String str = (sa[i] != null) ? sa[i] : ""; - out.writeUTF(str); - } - } -} +/* + * Copyright (c) 2001, 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 build.tools.generatecurrencydata; + +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.DataOutputStream; +import java.io.FileOutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Properties; +import java.util.TimeZone; + +/** + * Reads currency data in properties format from the file specified in the + * command line and generates a binary data file as specified in the command line. + * + * Output of this tool is a binary file that contains the data in + * the following order: + * + * - magic number (int): always 0x43757244 ('CurD') + * - formatVersion (int) + * - dataVersion (int) + * - mainTable (int[26*26]) + * - specialCaseCount (int) + * - specialCaseCutOverTimes (long[specialCaseCount]) + * - specialCaseOldCurrencies (String[specialCaseCount]) + * - specialCaseNewCurrencies (String[specialCaseCount]) + * - specialCaseOldCurrenciesDefaultFractionDigits (int[specialCaseCount]) + * - specialCaseNewCurrenciesDefaultFractionDigits (int[specialCaseCount]) + * - specialCaseOldCurrenciesNumericCode (int[specialCaseCount]) + * - specialCaseNewCurrenciesNumericCode (int[specialCaseCount]) + * - otherCurrenciesCount (int) + * - otherCurrencies (String) + * - otherCurrenciesDefaultFractionDigits (int[otherCurrenciesCount]) + * - otherCurrenciesNumericCode (int[otherCurrenciesCount]) + * + * See CurrencyData.properties for the input format description and + * Currency.java for the format descriptions of the generated tables. + */ +public class GenerateCurrencyData { + + private static DataOutputStream out; + + // input data: currency data obtained from properties on input stream + private static Properties currencyData; + private static String formatVersion; + private static String dataVersion; + private static String validCurrencyCodes; + + // handy constants - must match definitions in java.util.Currency + // magic number + private static final int MAGIC_NUMBER = 0x43757244; + // number of characters from A to Z + private static final int A_TO_Z = ('Z' - 'A') + 1; + // entry for invalid country codes + private static final int INVALID_COUNTRY_ENTRY = 0x0000007F; + // entry for countries without currency + private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200; + // mask for simple case country entries + private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000; + // mask for simple case country entry final character + private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F; + // mask for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0; + // shift count for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5; + // maximum number for simple case country entry default currency digits + private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9; + // mask for special case country entries + private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200; + // mask for special case country index + private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F; + // delta from entry index component in main table to index into special case tables + private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1; + // mask for distinguishing simple and special case countries + private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK; + // mask for the numeric code of the currency + private static final int NUMERIC_CODE_MASK = 0x000FFC00; + // shift count for the numeric code of the currency + private static final int NUMERIC_CODE_SHIFT = 10; + + // generated data + private static int[] mainTable = new int[A_TO_Z * A_TO_Z]; + + private static final int maxSpecialCases = 30; + private static int specialCaseCount = 0; + private static long[] specialCaseCutOverTimes = new long[maxSpecialCases]; + private static String[] specialCaseOldCurrencies = new String[maxSpecialCases]; + private static String[] specialCaseNewCurrencies = new String[maxSpecialCases]; + private static int[] specialCaseOldCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; + private static int[] specialCaseNewCurrenciesDefaultFractionDigits = new int[maxSpecialCases]; + private static int[] specialCaseOldCurrenciesNumericCode = new int[maxSpecialCases]; + private static int[] specialCaseNewCurrenciesNumericCode = new int[maxSpecialCases]; + + private static final int maxOtherCurrencies = 128; + private static int otherCurrenciesCount = 0; + private static StringBuffer otherCurrencies = new StringBuffer(); + private static int[] otherCurrenciesDefaultFractionDigits = new int[maxOtherCurrencies]; + private static int[] otherCurrenciesNumericCode= new int[maxOtherCurrencies]; + + // date format for parsing cut-over times + private static SimpleDateFormat format; + + // Minor Units + private static String[] currenciesWithDefinedMinorUnitDecimals = + new String[SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS + 1]; + private static String currenciesWithMinorUnitsUndefined; + + public static void main(String[] args) { + + // Look for "-o outputfilename" option + if ( args.length == 2 && args[0].equals("-o") ) { + try { + out = new DataOutputStream(new FileOutputStream(args[1])); + } catch ( FileNotFoundException e ) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(System.err); + System.exit(1); + } + } else { + System.err.println("Error: Illegal arg count"); + System.exit(1); + } + + format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + format.setLenient(false); + + try { + readInput(); + buildMainAndSpecialCaseTables(); + buildOtherTables(); + writeOutput(); + out.flush(); + out.close(); + } catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(System.err); + System.exit(1); + } + } + + private static void readInput() throws IOException { + currencyData = new Properties(); + currencyData.load(System.in); + + // initialize other lookup strings + formatVersion = (String) currencyData.get("formatVersion"); + dataVersion = (String) currencyData.get("dataVersion"); + validCurrencyCodes = (String) currencyData.get("all"); + for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { + currenciesWithDefinedMinorUnitDecimals[i] + = (String) currencyData.get("minor"+i); + } + currenciesWithMinorUnitsUndefined = (String) currencyData.get("minorUndefined"); + if (formatVersion == null || + dataVersion == null || + validCurrencyCodes == null || + currenciesWithMinorUnitsUndefined == null) { + throw new NullPointerException("not all required data is defined in input"); + } + } + + private static void buildMainAndSpecialCaseTables() throws Exception { + for (int first = 0; first < A_TO_Z; first++) { + for (int second = 0; second < A_TO_Z; second++) { + char firstChar = (char) ('A' + first); + char secondChar = (char) ('A' + second); + String countryCode = (new StringBuffer()).append(firstChar).append(secondChar).toString(); + String currencyInfo = (String) currencyData.get(countryCode); + int tableEntry = 0; + if (currencyInfo == null) { + // no entry -> must be invalid ISO 3166 country code + tableEntry = INVALID_COUNTRY_ENTRY; + } else { + int length = currencyInfo.length(); + if (length == 0) { + // special case: country without currency + tableEntry = COUNTRY_WITHOUT_CURRENCY_ENTRY; + } else if (length == 3) { + // valid currency + if (currencyInfo.charAt(0) == firstChar && currencyInfo.charAt(1) == secondChar) { + checkCurrencyCode(currencyInfo); + int digits = getDefaultFractionDigits(currencyInfo); + if (digits < 0 || digits > SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS) { + throw new RuntimeException("fraction digits out of range for " + currencyInfo); + } + int numericCode= getNumericCode(currencyInfo); + if (numericCode < 0 || numericCode >= 1000 ) { + throw new RuntimeException("numeric code out of range for " + currencyInfo); + } + tableEntry = SIMPLE_CASE_COUNTRY_MASK + | (currencyInfo.charAt(2) - 'A') + | (digits << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) + | (numericCode << NUMERIC_CODE_SHIFT); + } else { + tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); + } + } else { + tableEntry = SPECIAL_CASE_COUNTRY_MASK | (makeSpecialCaseEntry(currencyInfo) + SPECIAL_CASE_COUNTRY_INDEX_DELTA); + } + } + mainTable[first * A_TO_Z + second] = tableEntry; + } + } + } + + private static int getDefaultFractionDigits(String currencyCode) { + for (int i = 0; i <= SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS; i++) { + if (currenciesWithDefinedMinorUnitDecimals[i] != null && + currenciesWithDefinedMinorUnitDecimals[i].indexOf(currencyCode) != -1) { + return i; + } + } + + if (currenciesWithMinorUnitsUndefined.indexOf(currencyCode) != -1) { + return -1; + } else { + return 2; + } + } + + private static int getNumericCode(String currencyCode) { + int index = validCurrencyCodes.indexOf(currencyCode); + String numericCode = validCurrencyCodes.substring(index + 3, index + 6); + return Integer.parseInt(numericCode); + } + + static HashMap specialCaseMap = new HashMap<>(); + + private static int makeSpecialCaseEntry(String currencyInfo) throws Exception { + Integer oldEntry = specialCaseMap.get(currencyInfo); + if (oldEntry != null) { + return oldEntry.intValue(); + } + if (specialCaseCount == maxSpecialCases) { + throw new RuntimeException("too many special cases"); + } + if (currencyInfo.length() == 3) { + checkCurrencyCode(currencyInfo); + specialCaseCutOverTimes[specialCaseCount] = Long.MAX_VALUE; + specialCaseOldCurrencies[specialCaseCount] = currencyInfo; + specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(currencyInfo); + specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(currencyInfo); + specialCaseNewCurrencies[specialCaseCount] = null; + specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = 0; + specialCaseNewCurrenciesNumericCode[specialCaseCount] = 0; + } else { + int length = currencyInfo.length(); + if (currencyInfo.charAt(3) != ';' || + currencyInfo.charAt(length - 4) != ';') { + throw new RuntimeException("invalid currency info: " + currencyInfo); + } + String oldCurrency = currencyInfo.substring(0, 3); + String newCurrency = currencyInfo.substring(length - 3, length); + checkCurrencyCode(oldCurrency); + checkCurrencyCode(newCurrency); + String timeString = currencyInfo.substring(4, length - 4); + long time = format.parse(timeString).getTime(); + if (Math.abs(time - System.currentTimeMillis()) > ((long) 11) * 365 * 24 * 60 * 60 * 1000) { + throw new RuntimeException("time is more than 11 years from present: " + time); + } + specialCaseCutOverTimes[specialCaseCount] = time; + specialCaseOldCurrencies[specialCaseCount] = oldCurrency; + specialCaseOldCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(oldCurrency); + specialCaseOldCurrenciesNumericCode[specialCaseCount] = getNumericCode(oldCurrency); + specialCaseNewCurrencies[specialCaseCount] = newCurrency; + specialCaseNewCurrenciesDefaultFractionDigits[specialCaseCount] = getDefaultFractionDigits(newCurrency); + specialCaseNewCurrenciesNumericCode[specialCaseCount] = getNumericCode(newCurrency); + } + specialCaseMap.put(currencyInfo, new Integer(specialCaseCount)); + return specialCaseCount++; + } + + private static void buildOtherTables() { + if (validCurrencyCodes.length() % 7 != 6) { + throw new RuntimeException("\"all\" entry has incorrect size"); + } + for (int i = 0; i < (validCurrencyCodes.length() + 1) / 7; i++) { + if (i > 0 && validCurrencyCodes.charAt(i * 7 - 1) != '-') { + throw new RuntimeException("incorrect separator in \"all\" entry"); + } + String currencyCode = validCurrencyCodes.substring(i * 7, i * 7 + 3); + int numericCode = Integer.parseInt( + validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); + checkCurrencyCode(currencyCode); + int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; + if (tableEntry == INVALID_COUNTRY_ENTRY || + (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || + (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { + if (otherCurrenciesCount == maxOtherCurrencies) { + throw new RuntimeException("too many other currencies"); + } + if (otherCurrencies.length() > 0) { + otherCurrencies.append('-'); + } + otherCurrencies.append(currencyCode); + otherCurrenciesDefaultFractionDigits[otherCurrenciesCount] = getDefaultFractionDigits(currencyCode); + otherCurrenciesNumericCode[otherCurrenciesCount] = getNumericCode(currencyCode); + otherCurrenciesCount++; + } + } + } + + private static void checkCurrencyCode(String currencyCode) { + if (currencyCode.length() != 3) { + throw new RuntimeException("illegal length for currency code: " + currencyCode); + } + for (int i = 0; i < 3; i++) { + char aChar = currencyCode.charAt(i); + if ((aChar < 'A' || aChar > 'Z') && !currencyCode.equals("XB5")) { + throw new RuntimeException("currency code contains illegal character: " + currencyCode); + } + } + if (validCurrencyCodes.indexOf(currencyCode) == -1) { + throw new RuntimeException("currency code not listed as valid: " + currencyCode); + } + } + + private static void writeOutput() throws IOException { + out.writeInt(MAGIC_NUMBER); + out.writeInt(Integer.parseInt(formatVersion)); + out.writeInt(Integer.parseInt(dataVersion)); + writeIntArray(mainTable, mainTable.length); + out.writeInt(specialCaseCount); + writeLongArray(specialCaseCutOverTimes, specialCaseCount); + writeStringArray(specialCaseOldCurrencies, specialCaseCount); + writeStringArray(specialCaseNewCurrencies, specialCaseCount); + writeIntArray(specialCaseOldCurrenciesDefaultFractionDigits, specialCaseCount); + writeIntArray(specialCaseNewCurrenciesDefaultFractionDigits, specialCaseCount); + writeIntArray(specialCaseOldCurrenciesNumericCode, specialCaseCount); + writeIntArray(specialCaseNewCurrenciesNumericCode, specialCaseCount); + out.writeInt(otherCurrenciesCount); + out.writeUTF(otherCurrencies.toString()); + writeIntArray(otherCurrenciesDefaultFractionDigits, otherCurrenciesCount); + writeIntArray(otherCurrenciesNumericCode, otherCurrenciesCount); + } + + private static void writeIntArray(int[] ia, int count) throws IOException { + for (int i = 0; i < count; i ++) { + out.writeInt(ia[i]); + } + } + + private static void writeLongArray(long[] la, int count) throws IOException { + for (int i = 0; i < count; i ++) { + out.writeLong(la[i]); + } + } + + private static void writeStringArray(String[] sa, int count) throws IOException { + for (int i = 0; i < count; i ++) { + String str = (sa[i] != null) ? sa[i] : ""; + out.writeUTF(str); + } + } +} From c8af6084d988aaeffb616c9c0a3f7fe54a8b51d8 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Tue, 16 Apr 2024 15:32:03 -0500 Subject: [PATCH 05/18] D3DPipeline: removed some MSVCisms. A few ternary casts to LPCSTR that LLVM could not detect. New operator was fixed ages ago. --- jdk/src/windows/native/sun/java2d/d3d/D3DPipeline.h | 12 ++++++------ jdk/src/windows/native/sun/windows/awt.h | 2 +- jdk/src/windows/native/sun/windows/awt_Component.cpp | 2 +- .../windows/native/sun/windows/awt_PrintControl.cpp | 4 ++-- jdk/src/windows/native/sun/windows/awt_new.cpp | 11 ----------- 5 files changed, 10 insertions(+), 21 deletions(-) diff --git a/jdk/src/windows/native/sun/java2d/d3d/D3DPipeline.h b/jdk/src/windows/native/sun/java2d/d3d/D3DPipeline.h index 20019851ebf..fcf7f038e8c 100644 --- a/jdk/src/windows/native/sun/java2d/d3d/D3DPipeline.h +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DPipeline.h @@ -67,7 +67,7 @@ #include "Trace.h" #define DebugPrintD3DError(res, msg) \ - J2dTraceLn1(J2D_TRACE_ERROR, "D3D Error: " ## msg ## " res=%d", res) + J2dTraceLn1(J2D_TRACE_ERROR, "D3D Error: " msg " res=%d", res) #endif /*D3D_PPL_DLL*/ @@ -92,9 +92,9 @@ do { \ #define SAFE_PRINTLN(RES) \ do { \ if ((RES)!= NULL) { \ - J2dTraceLn1(J2D_TRACE_VERBOSE, " " ## #RES ## "=0x%x", (RES)); \ + J2dTraceLn1(J2D_TRACE_VERBOSE, " " #RES "=0x%x", (RES)); \ } else { \ - J2dTraceLn(J2D_TRACE_VERBOSE, " " ## #RES ## "=NULL"); \ + J2dTraceLn(J2D_TRACE_VERBOSE, " " #RES "=NULL"); \ } \ } while (0); #else // DEBUG @@ -109,7 +109,7 @@ do { \ #define ACT_IF_NULL(ACTION, value) \ if ((value) == NULL) { \ J2dTraceLn3(J2D_TRACE_ERROR, \ - "%s is null in %s:%d", #value, THIS_FILE, __LINE__); \ + "%s is null in %s:%d", #value, __FILE__, __LINE__); \ ACTION; \ } else do { } while (0) #define RETURN_IF_NULL(value) ACT_IF_NULL(return, value) @@ -119,12 +119,12 @@ do { \ #define RETURN_STATUS_IF_EXP_FAILED(EXPR) \ if (FAILED(res = (EXPR))) { \ - DebugPrintD3DError(res, " " ## #EXPR ## " failed in " ## THIS_FILE); \ + DebugPrintD3DError(res, " " #EXPR " failed in " __FILE__); \ return res; \ } else do { } while (0) #define RETURN_STATUS_IF_FAILED(status) \ if (FAILED((status))) { \ - DebugPrintD3DError((status), " failed in " ## THIS_FILE ## ", return;");\ + DebugPrintD3DError((status), " failed in " __FILE__ ", return;");\ return (status); \ } else do { } while (0) diff --git a/jdk/src/windows/native/sun/windows/awt.h b/jdk/src/windows/native/sun/windows/awt.h index e5332df63ab..8a447d1704c 100644 --- a/jdk/src/windows/native/sun/windows/awt.h +++ b/jdk/src/windows/native/sun/windows/awt.h @@ -336,7 +336,7 @@ class JavaStringBuffer jsize m_dwSize; LPWSTR getNonEmptyString() { return (NULL==m_pStr) - ? L"" + ? (LPWSTR)L"" : m_pStr; } diff --git a/jdk/src/windows/native/sun/windows/awt_Component.cpp b/jdk/src/windows/native/sun/windows/awt_Component.cpp index 44df115df57..fe3e91181eb 100644 --- a/jdk/src/windows/native/sun/windows/awt_Component.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Component.cpp @@ -3519,7 +3519,7 @@ UINT AwtComponent::WindowsKeyToJavaChar(UINT wkey, UINT modifiers, TransOps ops, } else { UINT scancode = ::MapVirtualKey(wkey, 0); converted = ::ToUnicodeEx(wkey, scancode, keyboardState, - wChar, 2, 0, GetKeyboardLayout()); + (LPWSTR)&wChar, 2, 0, GetKeyboardLayout()); } UINT translation; diff --git a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp index 0b228e82e6f..cf2b7a14d44 100644 --- a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp +++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp @@ -1018,7 +1018,7 @@ BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env, DASSERT(!IsBadReadPtr(devnames, sizeof(DEVNAMES))); LPTSTR lpcNames = (LPTSTR)devnames; LPTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ? - TEXT("") : lpcNames + devnames->wDeviceOffset); + (LPTSTR)TEXT("") : lpcNames + devnames->wDeviceOffset); if (pbuf != NULL) { jstring jstr = JNU_NewStringPlatform(env, pbuf); env->CallVoidMethod(printCtrl, @@ -1027,7 +1027,7 @@ BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env, env->DeleteLocalRef(jstr); } pbuf = (_tcslen(lpcNames + devnames->wOutputOffset) == 0 ? - TEXT("") : lpcNames + devnames->wOutputOffset); + (LPTSTR)TEXT("") : lpcNames + devnames->wOutputOffset); if (pbuf != NULL) { if (wcscmp(pbuf, L"FILE:") == 0) { pdFlags |= PD_PRINTTOFILE; diff --git a/jdk/src/windows/native/sun/windows/awt_new.cpp b/jdk/src/windows/native/sun/windows/awt_new.cpp index b2d133f2350..1636bdc2be6 100644 --- a/jdk/src/windows/native/sun/windows/awt_new.cpp +++ b/jdk/src/windows/native/sun/windows/awt_new.cpp @@ -114,17 +114,6 @@ void *safe_Realloc(void *memblock, size_t size) throw (std::bad_alloc) { return ret_val; } -#if !defined(DEBUG) -// This function exists because VC++ 5.0 currently does not conform to the -// Standard C++ specification which requires that operator new throw -// std::bad_alloc in an out of memory situation. Instead, VC++ 5.0 returns 0. -// -// This function can be safely removed when the problem is corrected. -void * CDECL operator new(size_t size) throw (std::bad_alloc) { - return safe_Malloc(size); -} -#endif - // This function is called at the beginning of an entry point. // Entry points are functions which are declared: // 1. CALLBACK, From 092f1ed99e6b657fe29078cd98ff920b46c3f632 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Wed, 17 Apr 2024 09:23:52 -0500 Subject: [PATCH 06/18] Import fix from latest JDK8u for OSX. This code isn't used but does need to build. --- .../native/java/lang/java_props_macosx.c | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/jdk/src/solaris/native/java/lang/java_props_macosx.c b/jdk/src/solaris/native/java/lang/java_props_macosx.c index b11a4d00143..273276a6319 100644 --- a/jdk/src/solaris/native/java/lang/java_props_macosx.c +++ b/jdk/src/solaris/native/java/lang/java_props_macosx.c @@ -180,39 +180,60 @@ typedef struct { NSInteger patchVersion; } OSVerStruct; -void setOSNameAndVersion(java_props_t *sprops) { +void setOSNameAndVersion(java_props_t* sprops) { // Hardcode os_name, and fill in os_version sprops->os_name = strdup("Mac OS X"); + NSString* nsVerStr = NULL; char* osVersionCStr = NULL; // Mac OS 10.9 includes the [NSProcessInfo operatingSystemVersion] function, - // but it's not in the 10.9 SDK. So, call it via objc_msgSend_stret. - if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) { - OSVerStruct (*procInfoFn)(id rec, SEL sel) = (OSVerStruct(*)(id, SEL))objc_msgSend_stret; - OSVerStruct osVer = procInfoFn([NSProcessInfo processInfo], - @selector(operatingSystemVersion)); - NSString *nsVerStr; - if (osVer.patchVersion == 0) { // Omit trailing ".0" - nsVerStr = [NSString stringWithFormat:@"%ld.%ld", + // but it's not in the 10.9 SDK. So, call it via NSInvocation. + if ([[NSProcessInfo processInfo]respondsToSelector:@selector(operatingSystemVersion)] ) { + OSVerStruct osVer; + NSMethodSignature* sig = [[NSProcessInfo processInfo]methodSignatureForSelector: + @selector(operatingSystemVersion)]; + NSInvocation* invoke = [NSInvocation invocationWithMethodSignature : sig]; + invoke.selector = @selector(operatingSystemVersion); + [invoke invokeWithTarget : [NSProcessInfo processInfo] ] ; + [invoke getReturnValue : &osVer] ; + + // Copy out the char* if running on version other than 10.16 Mac OS (10.16 == 11.x) + // or explicitly requesting version compatibility + if (!((long)osVer.majorVersion == 10 && (long)osVer.minorVersion >= 16) || + (getenv("SYSTEM_VERSION_COMPAT") != NULL)) { + if (osVer.patchVersion == 0) { // Omit trailing ".0" + nsVerStr = [NSString stringWithFormat : @"%ld.%ld", (long)osVer.majorVersion, (long)osVer.minorVersion]; - } else { - nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld", + } + else { + nsVerStr = [NSString stringWithFormat : @"%ld.%ld.%ld", (long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion]; + } + } + else { + // Version 10.16, without explicit env setting of SYSTEM_VERSION_COMPAT + // AKA 11+ Read the *real* ProductVersion from the hidden link to avoid SYSTEM_VERSION_COMPAT + // If not found, fallback below to the SystemVersion.plist + NSDictionary* version = [NSDictionary dictionaryWithContentsOfFile : + @"/System/Library/CoreServices/.SystemVersionPlatform.plist"]; + if (version != NULL) { + nsVerStr = [version objectForKey : @"ProductVersion"]; + } } - // Copy out the char* - osVersionCStr = strdup([nsVerStr UTF8String]); } // Fallback if running on pre-10.9 Mac OS - if (osVersionCStr == NULL) { - NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile : - @"/System/Library/CoreServices/SystemVersion.plist"]; + if (nsVerStr == NULL) { + NSDictionary* version = [NSDictionary dictionaryWithContentsOfFile : + @"/System/Library/CoreServices/SystemVersion.plist"]; if (version != NULL) { - NSString *nsVerStr = [version objectForKey : @"ProductVersion"]; - if (nsVerStr != NULL) { - osVersionCStr = strdup([nsVerStr UTF8String]); - } + nsVerStr = [version objectForKey : @"ProductVersion"]; } } + + if (nsVerStr != NULL) { + // Copy out the char* + osVersionCStr = strdup([nsVerStr UTF8String]); + } if (osVersionCStr == NULL) { osVersionCStr = strdup("Unknown"); } From b0d3e8ec414a5e92f9eb5c7fd8259b650af7ca03 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 28 Apr 2024 21:28:14 -0500 Subject: [PATCH 07/18] Fix from later OpenJDK for missing include. --- jdk/src/solaris/native/sun/management/MacosxOperatingSystem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/solaris/native/sun/management/MacosxOperatingSystem.c b/jdk/src/solaris/native/sun/management/MacosxOperatingSystem.c index 641b3863b9d..d77635a9253 100644 --- a/jdk/src/solaris/native/sun/management/MacosxOperatingSystem.c +++ b/jdk/src/solaris/native/sun/management/MacosxOperatingSystem.c @@ -29,6 +29,7 @@ #include #include +#include "jvm.h" JNIEXPORT jdouble JNICALL Java_sun_management_OperatingSystemImpl_getSystemCpuLoad From eb499f340add633f9562413429ece08381e390ef Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Tue, 30 Apr 2024 17:41:44 -0500 Subject: [PATCH 08/18] Deduplicate symbols to prevent compiler error. Backported. --- jdk/src/solaris/native/java/lang/childproc.c | 1 + jdk/src/solaris/native/java/lang/childproc.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/java/lang/childproc.c b/jdk/src/solaris/native/java/lang/childproc.c index 1d183cf1fb2..6b9a68b6d6e 100644 --- a/jdk/src/solaris/native/java/lang/childproc.c +++ b/jdk/src/solaris/native/java/lang/childproc.c @@ -33,6 +33,7 @@ #include "childproc.h" +const char *const *parentPathv; ssize_t restartableWrite(int fd, const void *buf, size_t count) diff --git a/jdk/src/solaris/native/java/lang/childproc.h b/jdk/src/solaris/native/java/lang/childproc.h index 75352a77b99..62795e8b9d1 100644 --- a/jdk/src/solaris/native/java/lang/childproc.h +++ b/jdk/src/solaris/native/java/lang/childproc.h @@ -119,7 +119,7 @@ typedef struct _SpawnInfo { * The cached and split version of the JDK's effective PATH. * (We don't support putenv("PATH=...") in native code) */ -const char * const *parentPathv; +extern const char *const *parentPathv; ssize_t restartableWrite(int fd, const void *buf, size_t count); int restartableDup2(int fd_from, int fd_to); From 06bf487d82c6aeaf296fd16db8bb69c417f4447c Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Wed, 1 May 2024 12:19:08 -0500 Subject: [PATCH 09/18] Missing header. Fixed in later version. --- jdk/src/share/native/common/jni_util.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/native/common/jni_util.c b/jdk/src/share/native/common/jni_util.c index 87cd00e5e14..6cd5571079d 100644 --- a/jdk/src/share/native/common/jni_util.c +++ b/jdk/src/share/native/common/jni_util.c @@ -29,6 +29,7 @@ #include "jvm.h" #include "jni.h" #include "jni_util.h" +#include "io_util.h" /* Due to a bug in the win32 C runtime library strings * such as "z:" need to be appended with a "." so we @@ -881,13 +882,13 @@ JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str) * VM can find it when loading system classes. * */ -extern int canonicalize(char *path, const char *out, int len); +extern int canonicalize0(char *path, const char *out, int len); JNIEXPORT int Canonicalize(JNIEnv *env, char *orig, char *out, int len) { /* canonicalize an already natived path */ - return canonicalize(orig, out, len); + return canonicalize0(orig, out, len); } JNIEXPORT jclass JNICALL From 89d28dc27bd89866178fb3600b36cb394990a202 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Thu, 2 May 2024 16:07:20 -0500 Subject: [PATCH 10/18] Revert name change. --- jdk/src/share/native/common/jni_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/native/common/jni_util.c b/jdk/src/share/native/common/jni_util.c index 6cd5571079d..0cf840cc0f0 100644 --- a/jdk/src/share/native/common/jni_util.c +++ b/jdk/src/share/native/common/jni_util.c @@ -882,13 +882,13 @@ JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str) * VM can find it when loading system classes. * */ -extern int canonicalize0(char *path, const char *out, int len); +extern int canonicalize(char *path, const char *out, int len); JNIEXPORT int Canonicalize(JNIEnv *env, char *orig, char *out, int len) { /* canonicalize an already natived path */ - return canonicalize0(orig, out, len); + return canonicalize(orig, out, len); } JNIEXPORT jclass JNICALL From 17ebb9b0115a7d7ff3b0970588fccf861a5870a6 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 4 May 2024 13:56:34 -0500 Subject: [PATCH 11/18] Export NET_AllocSockaddr. It's used from libnio on OSX. Not sure why it isn't exported. Looks like they don't use visibility=hidden on OSX? Probably. --- jdk/src/share/native/java/net/net_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/native/java/net/net_util.h b/jdk/src/share/native/java/net/net_util.h index c8a5e68c49f..e422453f256 100644 --- a/jdk/src/share/native/java/net/net_util.h +++ b/jdk/src/share/native/java/net/net_util.h @@ -131,7 +131,7 @@ jfieldID NET_GetFileDescriptorID(JNIEnv *env); JNIEXPORT jint JNICALL ipv6_available() ; -void +JNIEXPORT void JNICALL NET_AllocSockaddr(struct sockaddr **him, int *len); JNIEXPORT int JNICALL From da6f00101d0ec347cd0705fd14b8785968a5ef79 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 4 May 2024 21:37:36 -0500 Subject: [PATCH 12/18] Missing includes from later version. --- jdk/src/share/native/sun/security/krb5/nativeccache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/src/share/native/sun/security/krb5/nativeccache.c b/jdk/src/share/native/sun/security/krb5/nativeccache.c index beb5bf0262c..3c265cbf783 100644 --- a/jdk/src/share/native/sun/security/krb5/nativeccache.c +++ b/jdk/src/share/native/sun/security/krb5/nativeccache.c @@ -25,6 +25,8 @@ #import "sun_security_krb5_Credentials.h" #import +#import +#import /* * Based largely on klist.c, From 05400db82ed4aa88c36e569d34e3bf01622901c3 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 5 May 2024 09:45:07 -0500 Subject: [PATCH 13/18] Few missing includes and lack of guard defs. --- jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c | 1 + jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h | 5 +++++ jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c | 1 + jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h | 5 +++++ 4 files changed, 12 insertions(+) diff --git a/jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c b/jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c index 0b89f11c21e..2df8cb4c767 100644 --- a/jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c +++ b/jdk/src/solaris/native/sun/security/pkcs11/j2secmod_md.c @@ -32,6 +32,7 @@ #include #include "j2secmod.h" +#include "wrapper/pkcs11wrapper.h" void *findFunction(JNIEnv *env, jlong jHandle, const char *functionName) { void *hModule = (void*)jlong_to_ptr(jHandle); diff --git a/jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h b/jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h index 9a112181a8a..caabb9ecc34 100644 --- a/jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h +++ b/jdk/src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h @@ -56,6 +56,9 @@ /* defines for UNIX platforms *************************************************/ +#ifndef _P11_MD_H +#define _P11_MD_H 1 + #define CK_PTR * #define CK_DEFINE_FUNCTION(returnType, name) returnType name #define CK_DECLARE_FUNCTION(returnType, name) returnType name @@ -83,3 +86,5 @@ struct ModuleData { }; typedef struct ModuleData ModuleData; + +#endif /* _P11_MD_H */ diff --git a/jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c b/jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c index 33b11bfd07e..b7f9303a992 100644 --- a/jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c +++ b/jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.c @@ -30,6 +30,7 @@ #include #include "j2secmod.h" +#include "wrapper/pkcs11wrapper.h" void *findFunction(JNIEnv *env, jlong jHandle, const char *functionName) { HINSTANCE hModule = (HINSTANCE)jHandle; diff --git a/jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h b/jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h index 6f296e90790..68f3e330195 100644 --- a/jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h +++ b/jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h @@ -56,6 +56,9 @@ /* defines for WIN32 platform *************************************************/ +#ifndef _P11_MD_H +#define _P11_MD_H 1 + #include /* statement according to PKCS11 docu */ @@ -96,3 +99,5 @@ struct ModuleData { }; typedef struct ModuleData ModuleData; + +#endif /* _P11_MD_H */ From e9cf50c00fc44a2f9b544b3b3ad31d3923551df4 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Wed, 22 May 2024 08:52:40 -0500 Subject: [PATCH 14/18] Add option to disable execinfo.h on MUSL --- jdk/src/solaris/native/sun/xawt/XToolkit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/solaris/native/sun/xawt/XToolkit.c b/jdk/src/solaris/native/sun/xawt/XToolkit.c index 71d41f377fb..d9cab316b3c 100644 --- a/jdk/src/solaris/native/sun/xawt/XToolkit.c +++ b/jdk/src/solaris/native/sun/xawt/XToolkit.c @@ -27,7 +27,7 @@ #include #include #include -#ifdef __linux__ +#if defined __linux__ && !__MUSL__ #include #endif @@ -799,7 +799,7 @@ JNIEXPORT jstring JNICALL Java_sun_awt_X11_XToolkit_getEnv return ret; } -#ifdef __linux__ +#if defined __linux__ && !__MUSL__ void print_stack(void) { void *array[10]; From 093abf41ee786c5356721c85f074dd77187e98ca Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Wed, 22 May 2024 14:27:20 -0500 Subject: [PATCH 15/18] Missing include file. Added in later JDK versions. --- jdk/src/share/native/sun/java2d/opengl/OGLContext.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/src/share/native/sun/java2d/opengl/OGLContext.c b/jdk/src/share/native/sun/java2d/opengl/OGLContext.c index 14820c6c0b7..cac3895703b 100644 --- a/jdk/src/share/native/sun/java2d/opengl/OGLContext.c +++ b/jdk/src/share/native/sun/java2d/opengl/OGLContext.c @@ -38,6 +38,8 @@ #include "GraphicsPrimitiveMgr.h" #include "Region.h" +#include "jvm.h" + /** * The following methods are implemented in the windowing system (i.e. GLX * and WGL) source files. From e31ddd980b1a22a42a741b5a45e9723445f11bc1 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Wed, 5 Jun 2024 19:50:45 -0500 Subject: [PATCH 16/18] Should be lowercase. --- jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c index 8075d046763..ee861b24f3e 100644 --- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c +++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "jni.h" #include "jni_util.h" From 99464017c65e9f7d84f264d7986d129da1c66a64 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Fri, 14 Jun 2024 15:38:29 -0500 Subject: [PATCH 17/18] Implicit cast. --- .../native/sun/security/mscapi/security.cpp | 5202 ++++++++--------- 1 file changed, 2601 insertions(+), 2601 deletions(-) diff --git a/jdk/src/windows/native/sun/security/mscapi/security.cpp b/jdk/src/windows/native/sun/security/mscapi/security.cpp index 8ba36f5c02f..4451d229c64 100644 --- a/jdk/src/windows/native/sun/security/mscapi/security.cpp +++ b/jdk/src/windows/native/sun/security/mscapi/security.cpp @@ -1,2601 +1,2601 @@ -/* - * Copyright (c) 2005, 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. - */ - -//=--------------------------------------------------------------------------= -// security.cpp by Stanley Man-Kit Ho -//=--------------------------------------------------------------------------= -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include "sun_security_mscapi_CKey.h" -#include "sun_security_mscapi_CKeyStore.h" -#include "sun_security_mscapi_CRSACipher.h" -#include "sun_security_mscapi_CKeyPairGenerator_RSA.h" -#include "sun_security_mscapi_CPublicKey.h" -#include "sun_security_mscapi_CPublicKey_CRSAPublicKey.h" -#include "sun_security_mscapi_CSignature.h" -#include "sun_security_mscapi_CSignature_RSA.h" - - -#define OID_EKU_ANY "2.5.29.37.0" - -#define CERTIFICATE_PARSING_EXCEPTION \ - "java/security/cert/CertificateParsingException" -#define INVALID_KEY_EXCEPTION \ - "java/security/InvalidKeyException" -#define KEY_EXCEPTION "java/security/KeyException" -#define KEYSTORE_EXCEPTION "java/security/KeyStoreException" -#define PROVIDER_EXCEPTION "java/security/ProviderException" -#define SIGNATURE_EXCEPTION "java/security/SignatureException" -#define OUT_OF_MEMORY_ERROR "java/lang/OutOfMemoryError" - -#define SS_CHECK(Status) \ - if (Status != ERROR_SUCCESS) { \ - ThrowException(env, SIGNATURE_EXCEPTION, Status); \ - __leave; \ - } - -#define PP(fmt, ...) \ - if (trace) { \ - fprintf(stdout, "MSCAPI (%ld): ", __LINE__); \ - fprintf(stdout, fmt, ##__VA_ARGS__); \ - fprintf(stdout, "\n"); \ - fflush(stdout); \ - } - -extern "C" { - -char* trace = getenv("CAPI_TRACE"); - -void showProperty(NCRYPT_HANDLE hKey); - -void dump(LPSTR title, PBYTE data, DWORD len) -{ - if (trace) { - printf("==== %s ====\n", title); - for (DWORD i = 0; i < len; i+=16) { - printf("%04x: ", i); - for (int j = 0; j < 16; j++) { - if (j == 8) { - printf(" "); - } - if (i + j < len) { - printf("%02X ", *(data + i + j) & 0xff); - } else { - printf(" "); - } - } - for (int j = 0; j < 16; j++) { - if (i + j < len) { - int k = *(data + i + j) & 0xff; - if (k < 32 || k > 127) printf("."); - else printf("%c", (char)k); - } - } - printf("\n"); - } - fflush(stdout); - } -} - -/* - * Throws an arbitrary Java exception with the given message. - */ -void ThrowExceptionWithMessage(JNIEnv *env, const char *exceptionName, - const char *szMessage) -{ - jclass exceptionClazz = env->FindClass(exceptionName); - if (exceptionClazz != NULL) { - env->ThrowNew(exceptionClazz, szMessage); - } -} - -/* - * Throws an arbitrary Java exception. - * The exception message is a Windows system error message. - */ -void ThrowException(JNIEnv *env, const char *exceptionName, DWORD dwError) -{ - char szMessage[1024]; - szMessage[0] = '\0'; - - DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, - NULL, szMessage, sizeof(szMessage), NULL); - if (res == 0) { - strcpy(szMessage, "Unknown error"); - } - - ThrowExceptionWithMessage(env, exceptionName, szMessage); -} - -/* - * Overloaded 'operator new[]' variant, which will raise Java's - * OutOfMemoryError in the case of a failure. - */ -void* operator new[](std::size_t size, JNIEnv *env) -{ - void* buf = ::operator new[](size, std::nothrow); - if (buf == NULL) { - ThrowExceptionWithMessage(env, OUT_OF_MEMORY_ERROR, - "Native memory allocation failed"); - } - return buf; -} - -/* - * Maps the name of a hash algorithm to an algorithm identifier. - */ -ALG_ID MapHashAlgorithm(JNIEnv *env, jstring jHashAlgorithm) { - - const char* pszHashAlgorithm = NULL; - ALG_ID algId = 0; - - if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL)) - == NULL) { - return algId; - } - - if ((strcmp("SHA", pszHashAlgorithm) == 0) || - (strcmp("SHA1", pszHashAlgorithm) == 0) || - (strcmp("SHA-1", pszHashAlgorithm) == 0)) { - - algId = CALG_SHA1; - } else if (strcmp("SHA1+MD5", pszHashAlgorithm) == 0) { - algId = CALG_SSL3_SHAMD5; // a 36-byte concatenation of SHA-1 and MD5 - } else if (strcmp("SHA-256", pszHashAlgorithm) == 0) { - algId = CALG_SHA_256; - } else if (strcmp("SHA-384", pszHashAlgorithm) == 0) { - algId = CALG_SHA_384; - } else if (strcmp("SHA-512", pszHashAlgorithm) == 0) { - algId = CALG_SHA_512; - } else if (strcmp("MD5", pszHashAlgorithm) == 0) { - algId = CALG_MD5; - } else if (strcmp("MD2", pszHashAlgorithm) == 0) { - algId = CALG_MD2; - } - - if (pszHashAlgorithm) - env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm); - - return algId; -} - -/* - * Maps the name of a hash algorithm to a CNG Algorithm Identifier. - */ -LPCWSTR MapHashIdentifier(JNIEnv *env, jstring jHashAlgorithm) { - - const char* pszHashAlgorithm = NULL; - LPCWSTR id = NULL; - - if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL)) - == NULL) { - return id; - } - - if ((strcmp("SHA", pszHashAlgorithm) == 0) || - (strcmp("SHA1", pszHashAlgorithm) == 0) || - (strcmp("SHA-1", pszHashAlgorithm) == 0)) { - - id = BCRYPT_SHA1_ALGORITHM; - } else if (strcmp("SHA-256", pszHashAlgorithm) == 0) { - id = BCRYPT_SHA256_ALGORITHM; - } else if (strcmp("SHA-384", pszHashAlgorithm) == 0) { - id = BCRYPT_SHA384_ALGORITHM; - } else if (strcmp("SHA-512", pszHashAlgorithm) == 0) { - id = BCRYPT_SHA512_ALGORITHM; - } - - if (pszHashAlgorithm) - env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm); - - return id; -} - -/* - * Returns a certificate chain context given a certificate context and key - * usage identifier. - */ -bool GetCertificateChain(LPSTR lpszKeyUsageIdentifier, PCCERT_CONTEXT pCertContext, PCCERT_CHAIN_CONTEXT* ppChainContext) -{ - CERT_ENHKEY_USAGE EnhkeyUsage; - CERT_USAGE_MATCH CertUsage; - CERT_CHAIN_PARA ChainPara; - DWORD dwFlags = 0; - LPSTR szUsageIdentifierArray[1]; - - szUsageIdentifierArray[0] = lpszKeyUsageIdentifier; - EnhkeyUsage.cUsageIdentifier = 1; - EnhkeyUsage.rgpszUsageIdentifier = szUsageIdentifierArray; - CertUsage.dwType = USAGE_MATCH_TYPE_AND; - CertUsage.Usage = EnhkeyUsage; - ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); - ChainPara.RequestedUsage=CertUsage; - - // Build a chain using CertGetCertificateChain - // and the certificate retrieved. - return (::CertGetCertificateChain(NULL, // use the default chain engine - pCertContext, // pointer to the end certificate - NULL, // use the default time - NULL, // search no additional stores - &ChainPara, // use AND logic and enhanced key usage - // as indicated in the ChainPara - // data structure - dwFlags, - NULL, // currently reserved - ppChainContext) == TRUE); // return a pointer to the chain created -} - - -///////////////////////////////////////////////////////////////////////////// -// - -/* - * Class: sun_security_mscapi_PRNG - * Method: generateSeed - * Signature: (I[B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed - (JNIEnv *env, jclass clazz, jint length, jbyteArray seed) -{ - - HCRYPTPROV hCryptProv = NULL; - jbyte* reseedBytes = NULL; - jbyte* seedBytes = NULL; - jbyteArray result = NULL; - - __try - { - // Acquire a CSP context. - if(::CryptAcquireContext( //deprecated - &hCryptProv, - NULL, - NULL, - PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT) == FALSE) - { - ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); - __leave; - } - - /* - * If length is negative and a seed is supplied, use it to re-seed the - * generator. Return null whether a seed is supplied or not. - * If length is non-zero then generate a new seed according to the - * requested length and return the new seed. - * If length is zero then overwrite the supplied seed with a new - * seed of the same length and return the seed. - */ - if (length < 0) { - if (seed == NULL) { - __leave; - } - length = env->GetArrayLength(seed); - if ((reseedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { - __leave; - } - - if (::CryptGenRandom( //deprecated - hCryptProv, - length, - (BYTE *) reseedBytes) == FALSE) { - - ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); - __leave; - } - - result = NULL; - - } else { - - if (length > 0) { - seed = env->NewByteArray(length); - if (seed == NULL) { - __leave; - } - } else { - length = env->GetArrayLength(seed); - } - - if ((seedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { - __leave; - } - - if (::CryptGenRandom( //deprecated - hCryptProv, - length, - (BYTE *) seedBytes) == FALSE) { - - ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); - __leave; - } - - result = seed; // seed will be updated when seedBytes gets released - } - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (reseedBytes) - env->ReleaseByteArrayElements(seed, reseedBytes, JNI_ABORT); - - if (seedBytes) - env->ReleaseByteArrayElements(seed, seedBytes, 0); // update orig - - if (hCryptProv) - ::CryptReleaseContext(hCryptProv, 0); //deprecated - } - - return result; -} - - -/* - * Class: sun_security_mscapi_CKeyStore - * Method: loadKeysOrCertificateChains - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateChains - (JNIEnv *env, jobject obj, jstring jCertStoreName) -{ - /** - * Certificate in cert store has enhanced key usage extension - * property (or EKU property) that is not part of the certificate itself. To determine - * if the certificate should be returned, both the enhanced key usage in certificate - * extension block and the extension property stored along with the certificate in - * certificate store should be examined. Otherwise, we won't be able to determine - * the proper key usage from the Java side because the information is not stored as - * part of the encoded certificate. - */ - - const char* pszCertStoreName = NULL; - HCERTSTORE hCertStore = NULL; - PCCERT_CONTEXT pCertContext = NULL; - char* pszNameString = NULL; // certificate's friendly name - DWORD cchNameString = 0; - - - __try - { - // Open a system certificate store. - if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) - == NULL) { - __leave; - } - if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) - == NULL) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Determine clazz and method ID to generate certificate - jclass clazzArrayList = env->FindClass("java/util/ArrayList"); - if (clazzArrayList == NULL) { - __leave; - } - - jmethodID mNewArrayList = env->GetMethodID(clazzArrayList, "", "()V"); - if (mNewArrayList == NULL) { - __leave; - } - - jclass clazzOfThis = env->GetObjectClass(obj); - if (clazzOfThis == NULL) { - __leave; - } - - jmethodID mGenCert = env->GetMethodID(clazzOfThis, - "generateCertificate", - "([BLjava/util/Collection;)V"); - if (mGenCert == NULL) { - __leave; - } - - // Determine method ID to generate certificate chain - jmethodID mGenCertChain = env->GetMethodID(clazzOfThis, - "generateCertificateChain", - "(Ljava/lang/String;Ljava/util/Collection;)V"); - if (mGenCertChain == NULL) { - __leave; - } - - // Determine method ID to generate RSA certificate chain - jmethodID mGenKeyAndCertChain = env->GetMethodID(clazzOfThis, - "generateKeyAndCertificateChain", - "(ZLjava/lang/String;JJILjava/util/Collection;)V"); - if (mGenKeyAndCertChain == NULL) { - __leave; - } - - // Use CertEnumCertificatesInStore to get the certificates - // from the open store. pCertContext must be reset to - // NULL to retrieve the first certificate in the store. - while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext)) - { - PP("--------------------------"); - // Check if private key available - client authentication certificate - // must have private key available. - HCRYPTPROV hCryptProv = NULL; - DWORD dwKeySpec = 0; - HCRYPTKEY hUserKey = NULL; - BOOL bCallerFreeProv = FALSE; - BOOL bHasNoPrivateKey = FALSE; - DWORD dwPublicKeyLength = 0; - - // First, probe it silently - if (::CryptAcquireCertificatePrivateKey(pCertContext, - CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG, NULL, - &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE - && GetLastError() != NTE_SILENT_CONTEXT) - { - PP("bHasNoPrivateKey = TRUE!"); - bHasNoPrivateKey = TRUE; - } - else - { - if (bCallerFreeProv == TRUE) { - ::CryptReleaseContext(hCryptProv, NULL); // deprecated - bCallerFreeProv = FALSE; - } - - // Second, acquire the key normally (not silently) - if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL, - &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE) - { - PP("bHasNoPrivateKey = TRUE!!"); - bHasNoPrivateKey = TRUE; - } - else - { - if ((dwKeySpec & CERT_NCRYPT_KEY_SPEC) == CERT_NCRYPT_KEY_SPEC) { - PP("CNG %I64d", (__int64)hCryptProv); - } else { - // Private key is available - BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey); //deprecated - - // Skip certificate if cannot find private key - if (bGetUserKey == FALSE) { - if (bCallerFreeProv) - ::CryptReleaseContext(hCryptProv, NULL); // deprecated - continue; - } - - // Set cipher mode to ECB - DWORD dwCipherMode = CRYPT_MODE_ECB; - ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL); //deprecated - PP("CAPI %I64d %I64d", (__int64)hCryptProv, (__int64)hUserKey); - } - // If the private key is present in smart card, we may not be able to - // determine the key length by using the private key handle. However, - // since public/private key pairs must have the same length, we could - // determine the key length of the private key by using the public key - // in the certificate. - dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - &(pCertContext->pCertInfo->SubjectPublicKeyInfo)); - } - } - PCCERT_CHAIN_CONTEXT pCertChainContext = NULL; - - // Build certificate chain by using system certificate store. - // Add cert chain into collection for any key usage. - // - if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext)) - { - for (DWORD i = 0; i < pCertChainContext->cChain; i++) - { - // Found cert chain - PCERT_SIMPLE_CHAIN rgpChain = - pCertChainContext->rgpChain[i]; - - // Create ArrayList to store certs in each chain - jobject jArrayList = - env->NewObject(clazzArrayList, mNewArrayList); - if (jArrayList == NULL) { - __leave; - } - - // Cleanup the previous allocated name - if (pszNameString) { - delete [] pszNameString; - pszNameString = NULL; - } - - for (unsigned int j=0; j < rgpChain->cElement; j++) - { - PCERT_CHAIN_ELEMENT rgpElement = - rgpChain->rgpElement[j]; - PCCERT_CONTEXT pc = rgpElement->pCertContext; - - // Retrieve the friendly name of the first certificate - // in the chain - if (j == 0) { - - // If the cert's name cannot be retrieved then - // pszNameString remains set to NULL. - // (An alias name will be generated automatically - // when storing this cert in the keystore.) - - // Get length of friendly name - if ((cchNameString = CertGetNameString(pc, - CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, - NULL, 0)) > 1) { - - // Found friendly name - pszNameString = new (env) char[cchNameString]; - if (pszNameString == NULL) { - __leave; - } - - CertGetNameString(pc, - CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, - pszNameString, cchNameString); - } - } - - BYTE* pbCertEncoded = pc->pbCertEncoded; - DWORD cbCertEncoded = pc->cbCertEncoded; - - // Allocate and populate byte array - jbyteArray byteArray = env->NewByteArray(cbCertEncoded); - if (byteArray == NULL) { - __leave; - } - env->SetByteArrayRegion(byteArray, 0, cbCertEncoded, - (jbyte*) pbCertEncoded); - - // Generate certificate from byte array and store into - // cert collection - env->CallVoidMethod(obj, mGenCert, byteArray, jArrayList); - } - - // Usually pszNameString should be non-NULL. It's either - // the friendly name or an element from the subject name - // or SAN. - if (pszNameString) - { - PP("%s: %s", pszNameString, - pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); - if (bHasNoPrivateKey) - { - // Generate certificate chain and store into cert chain - // collection - jstring name = env->NewStringUTF(pszNameString); - if (name == NULL) { - __leave; - } - env->CallVoidMethod(obj, mGenCertChain, - name, - jArrayList); - } - else - { - if (hUserKey) { - // Only accept RSA for CAPI - DWORD dwData = CALG_RSA_KEYX; - DWORD dwSize = sizeof(DWORD); - ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData, //deprecated - &dwSize, NULL); - if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA) - { - // Generate RSA certificate chain and store into cert - // chain collection - jstring name = env->NewStringUTF(pszNameString); - if (name == NULL) { - __leave; - } - env->CallVoidMethod(obj, mGenKeyAndCertChain, - 1, - name, - (jlong) hCryptProv, (jlong) hUserKey, - dwPublicKeyLength, jArrayList); - } - } else { - // Only accept EC for CNG - BYTE buffer[32]; - DWORD len = 0; - if (::NCryptGetProperty( - hCryptProv, NCRYPT_ALGORITHM_PROPERTY, - (PBYTE)buffer, 32, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { - jstring name = env->NewStringUTF(pszNameString); - if (name == NULL) { - __leave; - } - if (buffer[0] == 'E' && buffer[2] == 'C' - && (dwPublicKeyLength == 256 - || dwPublicKeyLength == 384 - || dwPublicKeyLength == 521)) { - env->CallVoidMethod(obj, mGenKeyAndCertChain, - 0, - name, - (jlong) hCryptProv, (jlong) 0, - dwPublicKeyLength, jArrayList); - } else if (buffer[0] == 'R' && buffer[2] == 'S' - && buffer[4] == 'A') { - env->CallVoidMethod(obj, mGenKeyAndCertChain, - 1, - name, - (jlong) hCryptProv, (jlong) 0, - dwPublicKeyLength, jArrayList); - } else { - dump("Unknown NCRYPT_ALGORITHM_PROPERTY", buffer, len); - } - } - } - } - } - } - - // Free cert chain - if (pCertChainContext) - ::CertFreeCertificateChain(pCertChainContext); - } else { - PP("GetCertificateChain failed %d", GetLastError()); - } - } - } - __finally - { - if (hCertStore) - ::CertCloseStore(hCertStore, 0); - - if (pszCertStoreName) - env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); - - if (pszNameString) - delete [] pszNameString; - } -} - - -/* - * Class: sun_security_mscapi_CKey - * Method: cleanUp - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_sun_security_mscapi_CKey_cleanUp - (JNIEnv *env, jclass clazz, jlong hCryptProv, jlong hCryptKey) -{ - if (hCryptKey == NULL && hCryptProv != NULL) { - NCryptFreeObject((NCRYPT_HANDLE)hCryptProv); - } else { - if (hCryptKey != NULL) - ::CryptDestroyKey((HCRYPTKEY) hCryptKey); // deprecated - - if (hCryptProv != NULL) - ::CryptReleaseContext((HCRYPTPROV) hCryptProv, NULL); // deprecated - } -} - -/* - * Class: sun_security_mscapi_CSignature - * Method: signHash - * Signature: (Z[BILjava/lang/String;JJ)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signHash - (JNIEnv *env, jclass clazz, jboolean noHashOID, jbyteArray jHash, - jint jHashSize, jstring jHashAlgorithm, jlong hCryptProv, - jlong hCryptKey) -{ - HCRYPTHASH hHash = NULL; - jbyte* pHashBuffer = NULL; - jbyte* pSignedHashBuffer = NULL; - jbyteArray jSignedHash = NULL; - HCRYPTPROV hCryptProvAlt = NULL; - - __try - { - // Map hash algorithm - ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm); - - // Acquire a hash object handle. - if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) == FALSE) //deprecated - { - // Failover to using the PROV_RSA_AES CSP - - DWORD cbData = 256; - BYTE pbData[256]; - pbData[0] = '\0'; - - // Get name of the key container - ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER, //deprecated - (BYTE *)pbData, &cbData, 0); - - // Acquire an alternative CSP handle - if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL, //deprecated - PROV_RSA_AES, 0) == FALSE) - { - - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - - // Acquire a hash object handle. - if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0, //deprecated - &hHash) == FALSE) - { - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - } - - // Copy hash from Java to native buffer - pHashBuffer = new (env) jbyte[jHashSize]; - if (pHashBuffer == NULL) { - __leave; - } - env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); - - // Set hash value in the hash object - if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)pHashBuffer, NULL) == FALSE) //deprecated - { - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - - // Determine key spec. - DWORD dwKeySpec = AT_SIGNATURE; - ALG_ID dwAlgId; - DWORD dwAlgIdLen = sizeof(ALG_ID); - - if (! ::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) { //deprecated - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - - } - if (CALG_RSA_KEYX == dwAlgId) { - dwKeySpec = AT_KEYEXCHANGE; - } - - // Determine size of buffer - DWORD dwBufLen = 0; - DWORD dwFlags = 0; - - if (noHashOID == JNI_TRUE) { - dwFlags = CRYPT_NOHASHOID; // omit hash OID in NONEwithRSA signature - } - - if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, NULL, &dwBufLen) == FALSE) //deprecated - { - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - - pSignedHashBuffer = new (env) jbyte[dwBufLen]; - if (pSignedHashBuffer == NULL) { - __leave; - } - if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, (BYTE*)pSignedHashBuffer, &dwBufLen) == FALSE) //deprecated - { - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - - // Create new byte array - jbyteArray temp = env->NewByteArray(dwBufLen); - if (temp == NULL) { - __leave; - } - - // Copy data from native buffer - env->SetByteArrayRegion(temp, 0, dwBufLen, pSignedHashBuffer); - - jSignedHash = temp; - } - __finally - { - if (pSignedHashBuffer) - delete [] pSignedHashBuffer; - - if (pHashBuffer) - delete [] pHashBuffer; - - if (hHash) - ::CryptDestroyHash(hHash); //deprecated - - if (hCryptProvAlt) - ::CryptReleaseContext(hCryptProvAlt, 0); // deprecated - } - - return jSignedHash; -} - -/* - * Class: sun_security_mscapi_CSignature - * Method: signCngHash - * Signature: (I[BIILjava/lang/String;JJ)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signCngHash - (JNIEnv *env, jclass clazz, jint type, jbyteArray jHash, - jint jHashSize, jint saltLen, jstring jHashAlgorithm, jlong hCryptProv, - jlong hCryptKey) -{ - jbyteArray jSignedHash = NULL; - - jbyte* pHashBuffer = NULL; - jbyte* pSignedHashBuffer = NULL; - NCRYPT_KEY_HANDLE hk = NULL; - - __try - { - if (hCryptKey == 0) { - hk = (NCRYPT_KEY_HANDLE)hCryptProv; - } else { - SS_CHECK(::NCryptTranslateHandle( - NULL, - &hk, - (HCRYPTPROV)hCryptProv, - (HCRYPTKEY)hCryptKey, - NULL, - 0)); - } - - // Copy hash from Java to native buffer - pHashBuffer = new (env) jbyte[jHashSize]; - if (pHashBuffer == NULL) { - __leave; - } - env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); - - VOID* param; - DWORD dwFlags; - - switch (type) { - case 0: - param = NULL; - dwFlags = 0; - break; - case 1: - BCRYPT_PKCS1_PADDING_INFO pkcs1Info; - if (jHashAlgorithm) { - pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); - if (pkcs1Info.pszAlgId == NULL) { - ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, - "Unrecognised hash algorithm"); - __leave; - } - } else { - pkcs1Info.pszAlgId = NULL; - } - param = &pkcs1Info; - dwFlags = BCRYPT_PAD_PKCS1; - break; - case 2: - BCRYPT_PSS_PADDING_INFO pssInfo; - pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); - pssInfo.cbSalt = saltLen; - if (pssInfo.pszAlgId == NULL) { - ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, - "Unrecognised hash algorithm"); - __leave; - } - param = &pssInfo; - dwFlags = BCRYPT_PAD_PSS; - break; - } - - DWORD jSignedHashSize = 0; - SS_CHECK(::NCryptSignHash( - hk, - param, - (BYTE*)pHashBuffer, jHashSize, - NULL, 0, &jSignedHashSize, - dwFlags - )); - - pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; - if (pSignedHashBuffer == NULL) { - __leave; - } - - SS_CHECK(::NCryptSignHash( - hk, - param, - (BYTE*)pHashBuffer, jHashSize, - (BYTE*)pSignedHashBuffer, jSignedHashSize, &jSignedHashSize, - dwFlags - )); - - // Create new byte array - jbyteArray temp = env->NewByteArray(jSignedHashSize); - if (temp == NULL) { - __leave; - } - - // Copy data from native buffer - env->SetByteArrayRegion(temp, 0, jSignedHashSize, pSignedHashBuffer); - - jSignedHash = temp; - } - __finally - { - if (pSignedHashBuffer) - delete [] pSignedHashBuffer; - - if (pHashBuffer) - delete [] pHashBuffer; - - if (hCryptKey != 0 && hk != NULL) - ::NCryptFreeObject(hk); - } - - return jSignedHash; -} - -/* - * Class: sun_security_mscapi_CSignature - * Method: verifySignedHash - * Signature: ([BIL/java/lang/String;[BIJJ)Z - */ -JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifySignedHash - (JNIEnv *env, jclass clazz, jbyteArray jHash, jint jHashSize, - jstring jHashAlgorithm, jbyteArray jSignedHash, jint jSignedHashSize, - jlong hCryptProv, jlong hCryptKey) -{ - HCRYPTHASH hHash = NULL; - jbyte* pHashBuffer = NULL; - jbyte* pSignedHashBuffer = NULL; - DWORD dwSignedHashBufferLen = jSignedHashSize; - jboolean result = JNI_FALSE; - HCRYPTPROV hCryptProvAlt = NULL; - - __try - { - // Map hash algorithm - ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm); - - // Acquire a hash object handle. - if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) - == FALSE) - { - // Failover to using the PROV_RSA_AES CSP - - DWORD cbData = 256; - BYTE pbData[256]; - pbData[0] = '\0'; - - // Get name of the key container - ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER, //deprecated - (BYTE *)pbData, &cbData, 0); - - // Acquire an alternative CSP handle - if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL, //deprecated - PROV_RSA_AES, 0) == FALSE) - { - - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - - // Acquire a hash object handle. - if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0, - &hHash) == FALSE) - { - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - } - - // Copy hash and signedHash from Java to native buffer - pHashBuffer = new (env) jbyte[jHashSize]; - if (pHashBuffer == NULL) { - __leave; - } - env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); - - pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; - if (pSignedHashBuffer == NULL) { - __leave; - } - env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize, - pSignedHashBuffer); - - // Set hash value in the hash object - if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*) pHashBuffer, NULL) //deprecated - == FALSE) - { - ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); - __leave; - } - - // For RSA, the hash encryption algorithm is normally the same as the - // public key algorithm, so AT_SIGNATURE is used. - - // Verify the signature - if (::CryptVerifySignatureA(hHash, (BYTE *) pSignedHashBuffer, //deprecated - dwSignedHashBufferLen, (HCRYPTKEY) hCryptKey, NULL, 0) == TRUE) - { - result = JNI_TRUE; - } - } - - __finally - { - if (pSignedHashBuffer) - delete [] pSignedHashBuffer; - - if (pHashBuffer) - delete [] pHashBuffer; - - if (hHash) - ::CryptDestroyHash(hHash); //deprecated - - if (hCryptProvAlt) - ::CryptReleaseContext(hCryptProvAlt, 0); // deprecated - } - - return result; -} - -/* - * Class: sun_security_mscapi_CSignature - * Method: verifyCngSignedHash - * Signature: (I[BI[BIILjava/lang/String;JJ)Z - */ -JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifyCngSignedHash - (JNIEnv *env, jclass clazz, jint type, - jbyteArray jHash, jint jHashSize, - jbyteArray jSignedHash, jint jSignedHashSize, - jint saltLen, jstring jHashAlgorithm, - jlong hCryptProv, jlong hCryptKey) -{ - jbyte* pHashBuffer = NULL; - jbyte* pSignedHashBuffer = NULL; - jboolean result = JNI_FALSE; - NCRYPT_KEY_HANDLE hk = NULL; - - __try - { - if (hCryptKey == 0) { - hk = (NCRYPT_KEY_HANDLE)hCryptProv; - } else { - SS_CHECK(::NCryptTranslateHandle( - NULL, - &hk, - (HCRYPTPROV)hCryptProv, - (HCRYPTKEY)hCryptKey, - NULL, - 0)); - } - - // Copy hash and signedHash from Java to native buffer - pHashBuffer = new (env) jbyte[jHashSize]; - if (pHashBuffer == NULL) { - __leave; - } - env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); - - pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; - if (pSignedHashBuffer == NULL) { - __leave; - } - env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize, - pSignedHashBuffer); - - VOID* param; - DWORD dwFlags; - - switch (type) { - case 0: - param = NULL; - dwFlags = 0; - break; - case 1: - BCRYPT_PKCS1_PADDING_INFO pkcs1Info; - if (jHashAlgorithm) { - pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); - if (pkcs1Info.pszAlgId == NULL) { - ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, - "Unrecognised hash algorithm"); - __leave; - } - } else { - pkcs1Info.pszAlgId = NULL; - } - param = &pkcs1Info; - dwFlags = NCRYPT_PAD_PKCS1_FLAG; - break; - case 2: - BCRYPT_PSS_PADDING_INFO pssInfo; - pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); - pssInfo.cbSalt = saltLen; - if (pssInfo.pszAlgId == NULL) { - ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, - "Unrecognised hash algorithm"); - __leave; - } - param = &pssInfo; - dwFlags = NCRYPT_PAD_PSS_FLAG; - break; - } - - if (::NCryptVerifySignature(hk, param, - (BYTE *) pHashBuffer, jHashSize, - (BYTE *) pSignedHashBuffer, jSignedHashSize, - dwFlags) == ERROR_SUCCESS) - { - result = JNI_TRUE; - } - } - - __finally - { - if (pSignedHashBuffer) - delete [] pSignedHashBuffer; - - if (pHashBuffer) - delete [] pHashBuffer; - - if (hCryptKey != 0 && hk != NULL) - ::NCryptFreeObject(hk); - } - - return result; -} - -#define DUMP_PROP(p) \ - if (::NCryptGetProperty(hKey, p, (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { \ - sprintf(header, "%s %ls", #p, p); \ - dump(header, buffer, len); \ - } - -#define EXPORT_BLOB(p) \ - desc.cBuffers = 0; \ - if (::NCryptExportKey(hKey, NULL, p, &desc, (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { \ - sprintf(header, "%s %ls (%ld)", #p, p, desc.cBuffers); \ - dump(header, buffer, len); \ - for (int i = 0; i < (int)desc.cBuffers; i++) { \ - sprintf(header, "desc %ld", desc.pBuffers[i].BufferType); \ - dump(header, (PBYTE)desc.pBuffers[i].pvBuffer, desc.pBuffers[i].cbBuffer); \ - } \ - } - -void showProperty(NCRYPT_HANDLE hKey) { - char header[100]; - BYTE buffer[8192]; - DWORD len = 9; - NCryptBufferDesc desc; - DUMP_PROP(NCRYPT_ALGORITHM_GROUP_PROPERTY); - DUMP_PROP(NCRYPT_ALGORITHM_PROPERTY); - DUMP_PROP(NCRYPT_ASSOCIATED_ECDH_KEY); - DUMP_PROP(NCRYPT_BLOCK_LENGTH_PROPERTY); - DUMP_PROP(NCRYPT_CERTIFICATE_PROPERTY); - DUMP_PROP(NCRYPT_DH_PARAMETERS_PROPERTY); - DUMP_PROP(NCRYPT_EXPORT_POLICY_PROPERTY); - DUMP_PROP(NCRYPT_IMPL_TYPE_PROPERTY); - DUMP_PROP(NCRYPT_KEY_TYPE_PROPERTY); - DUMP_PROP(NCRYPT_KEY_USAGE_PROPERTY); - DUMP_PROP(NCRYPT_LAST_MODIFIED_PROPERTY); - DUMP_PROP(NCRYPT_LENGTH_PROPERTY); - DUMP_PROP(NCRYPT_LENGTHS_PROPERTY); - DUMP_PROP(NCRYPT_MAX_NAME_LENGTH_PROPERTY); - DUMP_PROP(NCRYPT_NAME_PROPERTY); - DUMP_PROP(NCRYPT_PIN_PROMPT_PROPERTY); - DUMP_PROP(NCRYPT_PIN_PROPERTY); - DUMP_PROP(NCRYPT_PROVIDER_HANDLE_PROPERTY); - DUMP_PROP(NCRYPT_READER_PROPERTY); - DUMP_PROP(NCRYPT_ROOT_CERTSTORE_PROPERTY); - DUMP_PROP(NCRYPT_SCARD_PIN_ID); - DUMP_PROP(NCRYPT_SCARD_PIN_INFO); - DUMP_PROP(NCRYPT_SECURE_PIN_PROPERTY); - DUMP_PROP(NCRYPT_SECURITY_DESCR_PROPERTY); - DUMP_PROP(NCRYPT_SECURITY_DESCR_SUPPORT_PROPERTY); - DUMP_PROP(NCRYPT_SMARTCARD_GUID_PROPERTY); - DUMP_PROP(NCRYPT_UI_POLICY_PROPERTY); - DUMP_PROP(NCRYPT_UNIQUE_NAME_PROPERTY); - DUMP_PROP(NCRYPT_USE_CONTEXT_PROPERTY); - DUMP_PROP(NCRYPT_USE_COUNT_ENABLED_PROPERTY); - DUMP_PROP(NCRYPT_USE_COUNT_PROPERTY); - DUMP_PROP(NCRYPT_USER_CERTSTORE_PROPERTY); - DUMP_PROP(NCRYPT_VERSION_PROPERTY); - DUMP_PROP(NCRYPT_WINDOW_HANDLE_PROPERTY); - - EXPORT_BLOB(BCRYPT_DH_PRIVATE_BLOB); - EXPORT_BLOB(BCRYPT_DH_PUBLIC_BLOB); - EXPORT_BLOB(BCRYPT_DSA_PRIVATE_BLOB); - EXPORT_BLOB(BCRYPT_DSA_PUBLIC_BLOB); - EXPORT_BLOB(BCRYPT_ECCPRIVATE_BLOB); - EXPORT_BLOB(BCRYPT_ECCPUBLIC_BLOB); - EXPORT_BLOB(BCRYPT_PUBLIC_KEY_BLOB); - EXPORT_BLOB(BCRYPT_PRIVATE_KEY_BLOB); - EXPORT_BLOB(BCRYPT_RSAFULLPRIVATE_BLOB); - EXPORT_BLOB(BCRYPT_RSAPRIVATE_BLOB); - EXPORT_BLOB(BCRYPT_RSAPUBLIC_BLOB); - EXPORT_BLOB(LEGACY_DH_PRIVATE_BLOB); - EXPORT_BLOB(LEGACY_DH_PUBLIC_BLOB); - EXPORT_BLOB(LEGACY_DSA_PRIVATE_BLOB); - EXPORT_BLOB(LEGACY_DSA_PUBLIC_BLOB); - EXPORT_BLOB(LEGACY_RSAPRIVATE_BLOB); - EXPORT_BLOB(LEGACY_RSAPUBLIC_BLOB); - // Support starts from Windows 8 and Windows Server 2012 - //EXPORT_BLOB(NCRYPT_CIPHER_KEY_BLOB); - EXPORT_BLOB(NCRYPT_OPAQUETRANSPORT_BLOB); - EXPORT_BLOB(NCRYPT_PKCS7_ENVELOPE_BLOB); - //EXPORT_BLOB(NCRYPTBUFFER_CERT_BLOB); - //EXPORT_BLOB(NCRYPT_PKCS8_PRIVATE_KEY_BLOB); - BCryptBuffer bb; - bb.BufferType = NCRYPTBUFFER_PKCS_SECRET; - bb.cbBuffer = 18; - bb.pvBuffer = L"changeit"; - BCryptBufferDesc bbd; - bbd.ulVersion = 0; - bbd.cBuffers = 1; - bbd.pBuffers = &bb; - if(::NCryptExportKey(hKey, NULL, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, - (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { - sprintf(header, "NCRYPT_PKCS8_PRIVATE_KEY_BLOB %ls", NCRYPT_PKCS8_PRIVATE_KEY_BLOB); - dump(header, buffer, len); - } - // Support starts from Windows 8 and Windows Server 2012 - //EXPORT_BLOB(NCRYPT_PROTECTED_KEY_BLOB); -} - -/* - * Class: sun_security_mscapi_CKeyPairGenerator_RSA - * Method: generateCKeyPair - * Signature: (Ljava/lang/String;ILjava/lang/String;)Lsun/security/mscapi/CKeyPair; - */ -JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyPairGenerator_00024RSA_generateCKeyPair - (JNIEnv *env, jclass clazz, jstring alg, jint keySize, jstring keyContainerName) -{ - HCRYPTPROV hCryptProv = NULL; - HCRYPTKEY hKeyPair; - DWORD dwFlags = (keySize << 16) | CRYPT_EXPORTABLE; - jobject keypair = NULL; - const char* pszKeyContainerName = NULL; // UUID - - __try - { - if ((pszKeyContainerName = - env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { - __leave; - } - - // Acquire a CSP context (create a new key container). - // Prefer a PROV_RSA_AES CSP, when available, due to its support - // for SHA-2-based signatures. - if (::CryptAcquireContext( //deprecated - &hCryptProv, - pszKeyContainerName, - NULL, - PROV_RSA_AES, - CRYPT_NEWKEYSET) == FALSE) - { - // Failover to using the default CSP (PROV_RSA_FULL) - - if (::CryptAcquireContext( //deprecated - &hCryptProv, - pszKeyContainerName, - NULL, - PROV_RSA_FULL, - CRYPT_NEWKEYSET) == FALSE) - { - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; - } - } - - // Generate an keypair - if(::CryptGenKey( //deprecated - hCryptProv, - AT_KEYEXCHANGE, - dwFlags, - &hKeyPair) == FALSE) - { - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; - } - - // Get the method ID for the CKeyPair constructor - jclass clazzCKeyPair = - env->FindClass("sun/security/mscapi/CKeyPair"); - if (clazzCKeyPair == NULL) { - __leave; - } - - jmethodID mNewCKeyPair = - env->GetMethodID(clazzCKeyPair, "", "(Ljava/lang/String;JJI)V"); - if (mNewCKeyPair == NULL) { - __leave; - } - - // Create a new keypair - keypair = env->NewObject(clazzCKeyPair, mNewCKeyPair, - alg, (jlong) hCryptProv, (jlong) hKeyPair, keySize); - - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (pszKeyContainerName) - env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); - } - - return keypair; -} - -/* - * Class: sun_security_mscapi_CKey - * Method: getContainerName - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_sun_security_mscapi_CKey_getContainerName - (JNIEnv *env, jclass jclazz, jlong hCryptProv) -{ - DWORD cbData = 256; - BYTE pbData[256]; - pbData[0] = '\0'; - - ::CryptGetProvParam( //deprecated - (HCRYPTPROV)hCryptProv, - PP_CONTAINER, - (BYTE *)pbData, - &cbData, - 0); - - return env->NewStringUTF((const char*)pbData); -} - -/* - * Class: sun_security_mscapi_CKey - * Method: getKeyType - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_sun_security_mscapi_CKey_getKeyType - (JNIEnv *env, jclass jclazz, jlong hCryptKey) -{ - ALG_ID dwAlgId; - DWORD dwAlgIdLen = sizeof(ALG_ID); - - if (::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) { //deprecated - - if (CALG_RSA_SIGN == dwAlgId) { - return env->NewStringUTF("Signature"); - - } else if (CALG_RSA_KEYX == dwAlgId) { - return env->NewStringUTF("Exchange"); - - } else { - char buffer[64]; - if (sprintf(buffer, "%lu", dwAlgId)) { - return env->NewStringUTF(buffer); - } - } - } - - return env->NewStringUTF(""); -} - -/* - * Class: sun_security_mscapi_CKeyStore - * Method: storeCertificate - * Signature: (Ljava/lang/String;Ljava/lang/String;[BIJJ)V - */ -JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_storeCertificate - (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName, - jbyteArray jCertEncoding, jint jCertEncodingSize, jlong hCryptProv, - jlong hCryptKey) -{ - const char* pszCertStoreName = NULL; - HCERTSTORE hCertStore = NULL; - PCCERT_CONTEXT pCertContext = NULL; - PWCHAR pszCertAliasName = NULL; - jbyte* pbCertEncoding = NULL; - const jchar* jCertAliasChars = NULL; - const char* pszContainerName = NULL; - const char* pszProviderName = NULL; - WCHAR * pwszContainerName = NULL; - WCHAR * pwszProviderName = NULL; - - __try - { - // Open a system certificate store. - if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) - == NULL) { - __leave; - } - if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Copy encoding from Java to native buffer - pbCertEncoding = new (env) jbyte[jCertEncodingSize]; - if (pbCertEncoding == NULL) { - __leave; - } - env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding); - - // Create a certificate context from the encoded cert - if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING, - (BYTE*) pbCertEncoding, jCertEncodingSize))) { - - ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError()); - __leave; - } - - // Set the certificate's friendly name - int size = env->GetStringLength(jCertAliasName); - pszCertAliasName = new (env) WCHAR[size + 1]; - if (pszCertAliasName == NULL) { - __leave; - } - - jCertAliasChars = env->GetStringChars(jCertAliasName, NULL); - if (jCertAliasChars == NULL) { - __leave; - } - memcpy(pszCertAliasName, jCertAliasChars, size * sizeof(WCHAR)); - pszCertAliasName[size] = 0; // append the string terminator - - CRYPT_DATA_BLOB friendlyName = { - sizeof(WCHAR) * (size + 1), - (BYTE *) pszCertAliasName - }; - - env->ReleaseStringChars(jCertAliasName, jCertAliasChars); - - if (! ::CertSetCertificateContextProperty(pCertContext, - CERT_FRIENDLY_NAME_PROP_ID, 0, &friendlyName)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Attach the certificate's private key (if supplied) - if (hCryptProv != 0 && hCryptKey != 0) { - - CRYPT_KEY_PROV_INFO keyProviderInfo; - DWORD dwDataLen; - - // Get the name of the key container - if (! ::CryptGetProvParam( //deprecated - (HCRYPTPROV) hCryptProv, - PP_CONTAINER, - NULL, - &dwDataLen, - 0)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - pszContainerName = new (env) char[dwDataLen]; - if (pszContainerName == NULL) { - __leave; - } - - if (! ::CryptGetProvParam( //deprecated - (HCRYPTPROV) hCryptProv, - PP_CONTAINER, - (BYTE *) pszContainerName, - &dwDataLen, - 0)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Convert to a wide char string - pwszContainerName = new (env) WCHAR[dwDataLen]; - if (pwszContainerName == NULL) { - __leave; - } - - if (mbstowcs(pwszContainerName, pszContainerName, dwDataLen) == 0) { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Set the name of the key container - keyProviderInfo.pwszContainerName = pwszContainerName; - - - // Get the name of the provider - if (! ::CryptGetProvParam( //deprecated - (HCRYPTPROV) hCryptProv, - PP_NAME, - NULL, - &dwDataLen, - 0)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - pszProviderName = new (env) char[dwDataLen]; - if (pszProviderName == NULL) { - __leave; - } - - if (! ::CryptGetProvParam( //deprecated - (HCRYPTPROV) hCryptProv, - PP_NAME, - (BYTE *) pszProviderName, - &dwDataLen, - 0)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Convert to a wide char string - pwszProviderName = new (env) WCHAR[dwDataLen]; - if (pwszProviderName == NULL) { - __leave; - } - - if (mbstowcs(pwszProviderName, pszProviderName, dwDataLen) == 0) { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Set the name of the provider - keyProviderInfo.pwszProvName = pwszProviderName; - - // Get and set the type of the provider - if (! ::CryptGetProvParam( //deprecated - (HCRYPTPROV) hCryptProv, - PP_PROVTYPE, - (LPBYTE) &keyProviderInfo.dwProvType, - &dwDataLen, - 0)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Set no provider flags - keyProviderInfo.dwFlags = 0; - - // Set no provider parameters - keyProviderInfo.cProvParam = 0; - keyProviderInfo.rgProvParam = NULL; - - // Get the key's algorithm ID - if (! ::CryptGetKeyParam( //deprecated - (HCRYPTKEY) hCryptKey, - KP_ALGID, - (LPBYTE) &keyProviderInfo.dwKeySpec, - &dwDataLen, - 0)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - // Set the key spec (using the algorithm ID). - switch (keyProviderInfo.dwKeySpec) { - case CALG_RSA_KEYX: - case CALG_DH_SF: - keyProviderInfo.dwKeySpec = AT_KEYEXCHANGE; - break; - - case CALG_RSA_SIGN: - case CALG_DSS_SIGN: - keyProviderInfo.dwKeySpec = AT_SIGNATURE; - break; - - default: - ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_ALGID); - __leave; - } - - if (! ::CertSetCertificateContextProperty(pCertContext, - CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProviderInfo)) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - } - - // Import encoded certificate - if (!::CertAddCertificateContextToStore(hCertStore, pCertContext, - CERT_STORE_ADD_REPLACE_EXISTING, NULL)) - { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (hCertStore) - ::CertCloseStore(hCertStore, 0); - - if (pszCertStoreName) - env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); - - if (pbCertEncoding) - delete [] pbCertEncoding; - - if (pszCertAliasName) - delete [] pszCertAliasName; - - if (pszContainerName) - delete [] pszContainerName; - - if (pwszContainerName) - delete [] pwszContainerName; - - if (pszProviderName) - delete [] pszProviderName; - - if (pwszProviderName) - delete [] pwszProviderName; - - if (pCertContext) - ::CertFreeCertificateContext(pCertContext); - } -} - -/* - * Class: sun_security_mscapi_CKeyStore - * Method: removeCertificate - * Signature: (Ljava/lang/String;Ljava/lang/String;[BI)V - */ -JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_removeCertificate - (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName, - jbyteArray jCertEncoding, jint jCertEncodingSize) { - - const char* pszCertStoreName = NULL; - const char* pszCertAliasName = NULL; - HCERTSTORE hCertStore = NULL; - PCCERT_CONTEXT pCertContext = NULL; - PCCERT_CONTEXT pTBDCertContext = NULL; - jbyte* pbCertEncoding = NULL; - DWORD cchNameString = 0; - char* pszNameString = NULL; // certificate's friendly name - BOOL bDeleteAttempted = FALSE; - - __try - { - // Open a system certificate store. - if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) - == NULL) { - __leave; - } - if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Copy encoding from Java to native buffer - pbCertEncoding = new (env) jbyte[jCertEncodingSize]; - if (pbCertEncoding == NULL) { - __leave; - } - env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding); - - // Create a certificate context from the encoded cert - if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING, - (BYTE*) pbCertEncoding, jCertEncodingSize))) { - - ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError()); - __leave; - } - - // Find the certificate to be deleted - if (!(pTBDCertContext = ::CertFindCertificateInStore(hCertStore, - X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext, NULL))) { - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Check that its friendly name matches the supplied alias - if ((cchNameString = ::CertGetNameString(pTBDCertContext, - CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, NULL, 0)) > 1) { - - pszNameString = new (env) char[cchNameString]; - if (pszNameString == NULL) { - __leave; - } - - ::CertGetNameString(pTBDCertContext, - CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszNameString, - cchNameString); - - // Compare the certificate's friendly name with supplied alias name - if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL)) - == NULL) { - __leave; - } - if (strcmp(pszCertAliasName, pszNameString) == 0) { - - // Only delete the certificate if the alias names matches - if (! ::CertDeleteCertificateFromStore(pTBDCertContext)) { - - // pTBDCertContext is always freed by the - // CertDeleteCertificateFromStore method - bDeleteAttempted = TRUE; - - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - } - } - - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (hCertStore) - ::CertCloseStore(hCertStore, 0); - - if (pszCertStoreName) - env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); - - if (pszCertAliasName) - env->ReleaseStringUTFChars(jCertAliasName, pszCertAliasName); - - if (pbCertEncoding) - delete [] pbCertEncoding; - - if (pszNameString) - delete [] pszNameString; - - if (pCertContext) - ::CertFreeCertificateContext(pCertContext); - - if (bDeleteAttempted && pTBDCertContext) - ::CertFreeCertificateContext(pTBDCertContext); - } -} - -/* - * Class: sun_security_mscapi_CKeyStore - * Method: destroyKeyContainer - * Signature: (Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_destroyKeyContainer - (JNIEnv *env, jobject clazz, jstring keyContainerName) -{ - HCRYPTPROV hCryptProv = NULL; - const char* pszKeyContainerName = NULL; - - __try - { - if ((pszKeyContainerName = - env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { - __leave; - } - - // Destroying the default key container is not permitted - // (because it may contain more one keypair). - if (pszKeyContainerName == NULL) { - - ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_KEYSET_PARAM); - __leave; - } - - // Acquire a CSP context (to the key container). - if (::CryptAcquireContext( //deprecated - &hCryptProv, - pszKeyContainerName, - NULL, - PROV_RSA_FULL, - CRYPT_DELETEKEYSET) == FALSE) - { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (pszKeyContainerName) - env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); - } -} - -/* - * Class: sun_security_mscapi_CRSACipher - * Method: encryptDecrypt - * Signature: ([BIJZ)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt - (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey, - jboolean doEncrypt) -{ - jbyteArray result = NULL; - jbyte* pData = NULL; - DWORD dwDataLen = jDataSize; - DWORD dwBufLen = env->GetArrayLength(jData); - DWORD i; - BYTE tmp; - - __try - { - // Copy data from Java buffer to native buffer - pData = new (env) jbyte[dwBufLen]; - if (pData == NULL) { - __leave; - } - env->GetByteArrayRegion(jData, 0, dwBufLen, pData); - - if (doEncrypt == JNI_TRUE) { - // encrypt - if (! ::CryptEncrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated - &dwDataLen, dwBufLen)) { - - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; - } - dwBufLen = dwDataLen; - - // convert from little-endian - for (i = 0; i < dwBufLen / 2; i++) { - tmp = pData[i]; - pData[i] = pData[dwBufLen - i -1]; - pData[dwBufLen - i - 1] = tmp; - } - } else { - // convert to little-endian - for (i = 0; i < dwBufLen / 2; i++) { - tmp = pData[i]; - pData[i] = pData[dwBufLen - i -1]; - pData[dwBufLen - i - 1] = tmp; - } - - // decrypt - if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated - &dwBufLen)) { - - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; - } - } - - // Create new byte array - if ((result = env->NewByteArray(dwBufLen)) == NULL) { - __leave; - } - - // Copy data from native buffer to Java buffer - env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData); - } - __finally - { - if (pData) - delete [] pData; - } - - return result; -} - -/* - * Class: sun_security_mscapi_CPublicKey - * Method: getPublicKeyBlob - * Signature: (JJ)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_getPublicKeyBlob - (JNIEnv *env, jobject clazz, jlong hCryptProv, jlong hCryptKey) { - - jbyteArray blob = NULL; - DWORD dwBlobLen; - BYTE* pbKeyBlob = NULL; - - __try - { - - // Determine the size of the blob - if (hCryptKey == 0) { - SS_CHECK(::NCryptExportKey( - (NCRYPT_KEY_HANDLE)hCryptProv, NULL, BCRYPT_ECCPUBLIC_BLOB, - NULL, NULL, 0, &dwBlobLen, NCRYPT_SILENT_FLAG)); - } else { - if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, NULL, //deprecated - &dwBlobLen)) { - - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; - } - } - - pbKeyBlob = new (env) BYTE[dwBlobLen]; - if (pbKeyBlob == NULL) { - __leave; - } - - // Generate key blob - if (hCryptKey == 0) { - SS_CHECK(::NCryptExportKey( - (NCRYPT_KEY_HANDLE)hCryptProv, NULL, BCRYPT_ECCPUBLIC_BLOB, - NULL, pbKeyBlob, dwBlobLen, &dwBlobLen, NCRYPT_SILENT_FLAG)); - } else { - if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, //deprecated - pbKeyBlob, &dwBlobLen)) { - - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; - } - } - - // Create new byte array - if ((blob = env->NewByteArray(dwBlobLen)) == NULL) { - __leave; - } - - // Copy data from native buffer to Java buffer - env->SetByteArrayRegion(blob, 0, dwBlobLen, (jbyte*) pbKeyBlob); - } - __finally - { - if (pbKeyBlob) - delete [] pbKeyBlob; - } - - return blob; -} - -/* - * Class: sun_security_mscapi_CPublicKey_CRSAPublicKey - * Method: getExponent - * Signature: ([B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_00024CRSAPublicKey_getExponent - (JNIEnv *env, jobject clazz, jbyteArray jKeyBlob) { - - jbyteArray exponent = NULL; - jbyte* exponentBytes = NULL; - jbyte* keyBlob = NULL; - - __try { - - jsize length = env->GetArrayLength(jKeyBlob); - jsize headerLength = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); - - if (length < headerLength) { - ThrowExceptionWithMessage(env, KEY_EXCEPTION, "Invalid BLOB"); - __leave; - } - - if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) { - __leave; - } - - PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob; - - // Check BLOB type - if (pPublicKeyStruc->bType != PUBLICKEYBLOB) { - ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE); - __leave; - } - - RSAPUBKEY* pRsaPubKey = - (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC)); - - int len = sizeof(pRsaPubKey->pubexp); - exponentBytes = new (env) jbyte[len]; - if (exponentBytes == NULL) { - __leave; - } - - // convert from little-endian while copying from blob - for (int i = 0, j = len - 1; i < len; i++, j--) { - exponentBytes[i] = ((BYTE*) &pRsaPubKey->pubexp)[j]; - } - - if ((exponent = env->NewByteArray(len)) == NULL) { - __leave; - } - env->SetByteArrayRegion(exponent, 0, len, exponentBytes); - } - __finally - { - if (keyBlob) - env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT); - - if (exponentBytes) - delete [] exponentBytes; - } - - return exponent; -} - -/* - * Class: sun_security_mscapi_CPublicKey_CRSAPublicKey - * Method: getModulus - * Signature: ([B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_00024CRSAPublicKey_getModulus - (JNIEnv *env, jobject clazz, jbyteArray jKeyBlob) { - - jbyteArray modulus = NULL; - jbyte* modulusBytes = NULL; - jbyte* keyBlob = NULL; - - __try { - - jsize length = env->GetArrayLength(jKeyBlob); - jsize headerLength = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); - - if (length < headerLength) { - ThrowExceptionWithMessage(env, KEY_EXCEPTION, "Invalid BLOB"); - __leave; - } - - if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) { - __leave; - } - - PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob; - - // Check BLOB type - if (pPublicKeyStruc->bType != PUBLICKEYBLOB) { - ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE); - __leave; - } - - RSAPUBKEY* pRsaPubKey = - (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC)); - - int len = pRsaPubKey->bitlen / 8; - if (len < 0 || len > length - headerLength) { - ThrowExceptionWithMessage(env, KEY_EXCEPTION, "Invalid key length"); - __leave; - } - - modulusBytes = new (env) jbyte[len]; - if (modulusBytes == NULL) { - __leave; - } - BYTE * pbModulus = (BYTE *) (keyBlob + headerLength); - - // convert from little-endian while copying from blob - for (int i = 0, j = len - 1; i < len; i++, j--) { - modulusBytes[i] = pbModulus[j]; - } - - if ((modulus = env->NewByteArray(len)) == NULL) { - __leave; - } - env->SetByteArrayRegion(modulus, 0, len, modulusBytes); - } - __finally - { - if (keyBlob) - env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT); - - if (modulusBytes) - delete [] modulusBytes; - } - - return modulus; -} - -/* - * Convert an array in big-endian byte order into little-endian byte order. - */ -int convertToLittleEndian(JNIEnv *env, jbyteArray source, jbyte* destination, - int destinationLength) { - - int result = -1; - jbyte* sourceBytes = NULL; - - __try { - int sourceLength = env->GetArrayLength(source); - - sourceBytes = env->GetByteArrayElements(source, 0); - if (sourceBytes == NULL) { - __leave; - } - - int copyLen = sourceLength; - if (sourceLength > destinationLength) { - // source might include an extra sign byte - if (sourceLength == destinationLength + 1 && sourceBytes[0] == 0) { - copyLen--; - } else { - __leave; - } - } - - // Copy bytes from the end of the source array to the beginning of the - // destination array (until the destination array is full). - // This ensures that the sign byte from the source array will be excluded. - for (int i = 0; i < copyLen; i++) { - destination[i] = sourceBytes[sourceLength - 1 - i]; - } - if (copyLen < destinationLength) { - memset(destination + copyLen, 0, destinationLength - copyLen); - } - result = destinationLength; - } __finally { - // Clean up. - if (sourceBytes) { - env->ReleaseByteArrayElements(source, sourceBytes, JNI_ABORT); - } - } - - return result; -} - -/* - * The Microsoft Base Cryptographic Provider supports public-key BLOBs - * that have the following format: - * - * PUBLICKEYSTRUC publickeystruc; - * RSAPUBKEY rsapubkey; - * BYTE modulus[rsapubkey.bitlen/8]; - * - * and private-key BLOBs that have the following format: - * - * PUBLICKEYSTRUC publickeystruc; - * RSAPUBKEY rsapubkey; - * BYTE modulus[rsapubkey.bitlen/8]; - * BYTE prime1[rsapubkey.bitlen/16]; - * BYTE prime2[rsapubkey.bitlen/16]; - * BYTE exponent1[rsapubkey.bitlen/16]; - * BYTE exponent2[rsapubkey.bitlen/16]; - * BYTE coefficient[rsapubkey.bitlen/16]; - * BYTE privateExponent[rsapubkey.bitlen/8]; - * - * This method generates such BLOBs from the key elements supplied. - */ -jbyteArray generateKeyBlob( - JNIEnv *env, - jint jKeyBitLength, - jbyteArray jModulus, - jbyteArray jPublicExponent, - jbyteArray jPrivateExponent, - jbyteArray jPrimeP, - jbyteArray jPrimeQ, - jbyteArray jExponentP, - jbyteArray jExponentQ, - jbyteArray jCrtCoefficient) -{ - jsize jKeyByteLength = jKeyBitLength / 8; - jsize jBlobLength; - BOOL bGeneratePrivateKeyBlob; - - // Determine whether to generate a public-key or a private-key BLOB - if (jPrivateExponent != NULL && - jPrimeP != NULL && - jPrimeQ != NULL && - jExponentP != NULL && - jExponentQ != NULL && - jCrtCoefficient != NULL) { - - bGeneratePrivateKeyBlob = TRUE; - jBlobLength = sizeof(BLOBHEADER) + - sizeof(RSAPUBKEY) + - ((jKeyBitLength / 8) * 4) + - (jKeyBitLength / 16); - - } else { - bGeneratePrivateKeyBlob = FALSE; - jBlobLength = sizeof(BLOBHEADER) + - sizeof(RSAPUBKEY) + - (jKeyBitLength / 8); - } - - jbyte* jBlobBytes = NULL; - jbyte* jBlobElement; - jbyteArray jBlob = NULL; - jsize jElementLength; - - __try { - jBlobBytes = new (env) jbyte[jBlobLength]; - if (jBlobBytes == NULL) { - __leave; - } - - BLOBHEADER *pBlobHeader = (BLOBHEADER *) jBlobBytes; - if (bGeneratePrivateKeyBlob) { - pBlobHeader->bType = PRIVATEKEYBLOB; // 0x07 - } else { - pBlobHeader->bType = PUBLICKEYBLOB; // 0x06 - } - pBlobHeader->bVersion = CUR_BLOB_VERSION; // 0x02 - pBlobHeader->reserved = 0; // 0x0000 - pBlobHeader->aiKeyAlg = CALG_RSA_KEYX; // 0x0000a400 - - RSAPUBKEY *pRsaPubKey = - (RSAPUBKEY *) (jBlobBytes + sizeof(PUBLICKEYSTRUC)); - if (bGeneratePrivateKeyBlob) { - pRsaPubKey->magic = 0x32415352; // "RSA2" - } else { - pRsaPubKey->magic = 0x31415352; // "RSA1" - } - pRsaPubKey->bitlen = jKeyBitLength; - pRsaPubKey->pubexp = 0; // init - - // Sanity check - jsize jPublicExponentLength = env->GetArrayLength(jPublicExponent); - if (jPublicExponentLength > sizeof(pRsaPubKey->pubexp)) { - ThrowException(env, INVALID_KEY_EXCEPTION, NTE_BAD_TYPE); - __leave; - } - // The length argument must be the smaller of jPublicExponentLength - // and sizeof(pRsaPubKey->pubkey) - if ((jElementLength = convertToLittleEndian(env, jPublicExponent, - (jbyte *) &(pRsaPubKey->pubexp), jPublicExponentLength)) < 0) { - __leave; - } - - // Modulus n - jBlobElement = - (jbyte *) (jBlobBytes + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); - if ((jElementLength = convertToLittleEndian(env, jModulus, jBlobElement, - jKeyByteLength)) < 0) { - __leave; - } - - if (bGeneratePrivateKeyBlob) { - // Prime p - jBlobElement += jElementLength; - if ((jElementLength = convertToLittleEndian(env, jPrimeP, - jBlobElement, jKeyByteLength / 2)) < 0) { - __leave; - } - - // Prime q - jBlobElement += jElementLength; - if ((jElementLength = convertToLittleEndian(env, jPrimeQ, - jBlobElement, jKeyByteLength / 2)) < 0) { - __leave; - } - - // Prime exponent p - jBlobElement += jElementLength; - if ((jElementLength = convertToLittleEndian(env, jExponentP, - jBlobElement, jKeyByteLength / 2)) < 0) { - __leave; - } - - // Prime exponent q - jBlobElement += jElementLength; - if ((jElementLength = convertToLittleEndian(env, jExponentQ, - jBlobElement, jKeyByteLength / 2)) < 0) { - __leave; - } - - // CRT coefficient - jBlobElement += jElementLength; - if ((jElementLength = convertToLittleEndian(env, jCrtCoefficient, - jBlobElement, jKeyByteLength / 2)) < 0) { - __leave; - } - - // Private exponent - jBlobElement += jElementLength; - if ((jElementLength = convertToLittleEndian(env, jPrivateExponent, - jBlobElement, jKeyByteLength)) < 0) { - __leave; - } - } - - if ((jBlob = env->NewByteArray(jBlobLength)) == NULL) { - __leave; - } - env->SetByteArrayRegion(jBlob, 0, jBlobLength, jBlobBytes); - - } - __finally - { - if (jBlobBytes) - delete [] jBlobBytes; - } - - return jBlob; -} - -/* - * Class: sun_security_mscapi_CKeyStore - * Method: generateRSAPrivateKeyBlob - * Signature: (I[B[B[B[B[B[B[B[B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CKeyStore_generateRSAPrivateKeyBlob - (JNIEnv *env, jobject clazz, - jint jKeyBitLength, - jbyteArray jModulus, - jbyteArray jPublicExponent, - jbyteArray jPrivateExponent, - jbyteArray jPrimeP, - jbyteArray jPrimeQ, - jbyteArray jExponentP, - jbyteArray jExponentQ, - jbyteArray jCrtCoefficient) -{ - return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent, - jPrivateExponent, jPrimeP, jPrimeQ, jExponentP, jExponentQ, - jCrtCoefficient); -} - -/* - * Class: sun_security_mscapi_CSignature_RSA - * Method: generatePublicKeyBlob - * Signature: (I[B[B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_00024RSA_generatePublicKeyBlob - (JNIEnv *env, jclass clazz, - jint jKeyBitLength, - jbyteArray jModulus, - jbyteArray jPublicExponent) -{ - return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent, - NULL, NULL, NULL, NULL, NULL, NULL); -} - -/* - * Class: sun_security_mscapi_CKeyStore - * Method: storePrivateKey - * Signature: (Ljava/lang/String;[BLjava/lang/String;I)Lsun/security/mscapi/CPrivateKey; - */ -JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyStore_storePrivateKey - (JNIEnv *env, jobject clazz, jstring alg, jbyteArray keyBlob, - jstring keyContainerName, jint keySize) -{ - HCRYPTPROV hCryptProv = NULL; - HCRYPTKEY hKey = NULL; - DWORD dwBlobLen; - BYTE * pbKeyBlob = NULL; - const char* pszKeyContainerName = NULL; // UUID - jobject privateKey = NULL; - - __try - { - if ((pszKeyContainerName = - env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { - __leave; - } - dwBlobLen = env->GetArrayLength(keyBlob); - if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) - == NULL) { - __leave; - } - - // Acquire a CSP context (create a new key container). - if (::CryptAcquireContext( //deprecated - &hCryptProv, - pszKeyContainerName, - NULL, - PROV_RSA_FULL, - CRYPT_NEWKEYSET) == FALSE) - { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Import the private key - if (::CryptImportKey( //deprecated - hCryptProv, - pbKeyBlob, - dwBlobLen, - 0, - CRYPT_EXPORTABLE, - &hKey) == FALSE) - { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Get the method ID for the CPrivateKey constructor - jclass clazzCPrivateKey = - env->FindClass("sun/security/mscapi/CPrivateKey"); - if (clazzCPrivateKey == NULL) { - __leave; - } - - jmethodID mNewCPrivateKey = - env->GetStaticMethodID(clazzCPrivateKey, "of", - "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPrivateKey;"); - if (mNewCPrivateKey == NULL) { - __leave; - } - - // Create a new private key - privateKey = env->CallStaticObjectMethod(clazzCPrivateKey, mNewCPrivateKey, - alg, (jlong) hCryptProv, (jlong) hKey, keySize); - - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (pszKeyContainerName) - env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); - - if (pbKeyBlob) - env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob, - JNI_ABORT); - } - - return privateKey; -} - -/* - * Class: sun_security_mscapi_CSignature - * Method: importECPublicKey - * Signature: (Ljava/lang/String;[BI)Lsun/security/mscapi/CPublicKey; - */ -JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CSignature_importECPublicKey - (JNIEnv *env, jclass clazz, jstring alg, jbyteArray keyBlob, jint keySize) -{ - BCRYPT_ALG_HANDLE hSignAlg = NULL; - NCRYPT_KEY_HANDLE hTmpKey = NULL; - DWORD dwBlobLen; - BYTE * pbKeyBlob = NULL; - jobject publicKey = NULL; - - __try - { - dwBlobLen = env->GetArrayLength(keyBlob); - if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) - == NULL) { - __leave; - } - dump("NCryptImportKey", pbKeyBlob, dwBlobLen); - NCRYPT_PROV_HANDLE hProv; - SS_CHECK(NCryptOpenStorageProvider( - &hProv, L"Microsoft Software Key Storage Provider", 0 )); - SS_CHECK(NCryptImportKey( - hProv, - NULL, - BCRYPT_ECCPUBLIC_BLOB, - NULL, - &hTmpKey, - pbKeyBlob, - dwBlobLen, - 0)); - NCryptFreeObject( hProv ); - // Get the method ID for the CPublicKey constructor - jclass clazzCPublicKey = - env->FindClass("sun/security/mscapi/CPublicKey"); - if (clazzCPublicKey == NULL) { - __leave; - } - - jmethodID mNewCPublicKey = - env->GetStaticMethodID(clazzCPublicKey, "of", - "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPublicKey;"); - if (mNewCPublicKey == NULL) { - __leave; - } - - // Create a new public key - publicKey = env->CallStaticObjectMethod(clazzCPublicKey, mNewCPublicKey, - alg, (jlong) hTmpKey, (jlong) 0, keySize); - } - __finally - { - } - - return publicKey; -} - -/* - * Class: sun_security_mscapi_CSignature - * Method: importPublicKey - * Signature: (Ljava/lang/String;[BI)Lsun/security/mscapi/CPublicKey; - */ -JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CSignature_importPublicKey - (JNIEnv *env, jclass clazz, jstring alg, jbyteArray keyBlob, jint keySize) -{ - HCRYPTPROV hCryptProv = NULL; - HCRYPTKEY hKey = NULL; - DWORD dwBlobLen; - BYTE * pbKeyBlob = NULL; - jobject publicKey = NULL; - - __try - { - dwBlobLen = env->GetArrayLength(keyBlob); - if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) - == NULL) { - __leave; - } - - // Acquire a CSP context (create a new key container). - // Prefer a PROV_RSA_AES CSP, when available, due to its support - // for SHA-2-based signatures. - if (::CryptAcquireContext( //deprecated - &hCryptProv, - NULL, - NULL, - PROV_RSA_AES, - CRYPT_VERIFYCONTEXT) == FALSE) - { - // Failover to using the default CSP (PROV_RSA_FULL) - - if (::CryptAcquireContext( //deprecated - &hCryptProv, - NULL, - NULL, - PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT) == FALSE) - { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - } - - // Import the public key - if (::CryptImportKey( //deprecated - hCryptProv, - pbKeyBlob, - dwBlobLen, - 0, - CRYPT_EXPORTABLE, - &hKey) == FALSE) - { - ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); - __leave; - } - - // Get the method ID for the CPublicKey constructor - jclass clazzCPublicKey = - env->FindClass("sun/security/mscapi/CPublicKey"); - if (clazzCPublicKey == NULL) { - __leave; - } - - jmethodID mNewCPublicKey = - env->GetStaticMethodID(clazzCPublicKey, "of", - "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPublicKey;"); - if (mNewCPublicKey == NULL) { - __leave; - } - - // Create a new public key - publicKey = env->CallStaticObjectMethod(clazzCPublicKey, mNewCPublicKey, - alg, (jlong) hCryptProv, (jlong) hKey, keySize); - - } - __finally - { - //-------------------------------------------------------------------- - // Clean up. - - if (pbKeyBlob) - env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob, - JNI_ABORT); - } - - return publicKey; -} - -} /* extern "C" */ +/* + * Copyright (c) 2005, 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. + */ + +//=--------------------------------------------------------------------------= +// security.cpp by Stanley Man-Kit Ho +//=--------------------------------------------------------------------------= +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sun_security_mscapi_CKey.h" +#include "sun_security_mscapi_CKeyStore.h" +#include "sun_security_mscapi_CRSACipher.h" +#include "sun_security_mscapi_CKeyPairGenerator_RSA.h" +#include "sun_security_mscapi_CPublicKey.h" +#include "sun_security_mscapi_CPublicKey_CRSAPublicKey.h" +#include "sun_security_mscapi_CSignature.h" +#include "sun_security_mscapi_CSignature_RSA.h" + + +#define OID_EKU_ANY "2.5.29.37.0" + +#define CERTIFICATE_PARSING_EXCEPTION \ + "java/security/cert/CertificateParsingException" +#define INVALID_KEY_EXCEPTION \ + "java/security/InvalidKeyException" +#define KEY_EXCEPTION "java/security/KeyException" +#define KEYSTORE_EXCEPTION "java/security/KeyStoreException" +#define PROVIDER_EXCEPTION "java/security/ProviderException" +#define SIGNATURE_EXCEPTION "java/security/SignatureException" +#define OUT_OF_MEMORY_ERROR "java/lang/OutOfMemoryError" + +#define SS_CHECK(Status) \ + if (Status != ERROR_SUCCESS) { \ + ThrowException(env, SIGNATURE_EXCEPTION, Status); \ + __leave; \ + } + +#define PP(fmt, ...) \ + if (trace) { \ + fprintf(stdout, "MSCAPI (%ld): ", __LINE__); \ + fprintf(stdout, fmt, ##__VA_ARGS__); \ + fprintf(stdout, "\n"); \ + fflush(stdout); \ + } + +extern "C" { + +char* trace = getenv("CAPI_TRACE"); + +void showProperty(NCRYPT_HANDLE hKey); + +void dump(LPSTR title, PBYTE data, DWORD len) +{ + if (trace) { + printf("==== %s ====\n", title); + for (DWORD i = 0; i < len; i+=16) { + printf("%04x: ", i); + for (int j = 0; j < 16; j++) { + if (j == 8) { + printf(" "); + } + if (i + j < len) { + printf("%02X ", *(data + i + j) & 0xff); + } else { + printf(" "); + } + } + for (int j = 0; j < 16; j++) { + if (i + j < len) { + int k = *(data + i + j) & 0xff; + if (k < 32 || k > 127) printf("."); + else printf("%c", (char)k); + } + } + printf("\n"); + } + fflush(stdout); + } +} + +/* + * Throws an arbitrary Java exception with the given message. + */ +void ThrowExceptionWithMessage(JNIEnv *env, const char *exceptionName, + const char *szMessage) +{ + jclass exceptionClazz = env->FindClass(exceptionName); + if (exceptionClazz != NULL) { + env->ThrowNew(exceptionClazz, szMessage); + } +} + +/* + * Throws an arbitrary Java exception. + * The exception message is a Windows system error message. + */ +void ThrowException(JNIEnv *env, const char *exceptionName, DWORD dwError) +{ + char szMessage[1024]; + szMessage[0] = '\0'; + + DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, + NULL, szMessage, sizeof(szMessage), NULL); + if (res == 0) { + strcpy(szMessage, "Unknown error"); + } + + ThrowExceptionWithMessage(env, exceptionName, szMessage); +} + +/* + * Overloaded 'operator new[]' variant, which will raise Java's + * OutOfMemoryError in the case of a failure. + */ +void* operator new[](std::size_t size, JNIEnv *env) +{ + void* buf = ::operator new[](size, std::nothrow); + if (buf == NULL) { + ThrowExceptionWithMessage(env, OUT_OF_MEMORY_ERROR, + "Native memory allocation failed"); + } + return buf; +} + +/* + * Maps the name of a hash algorithm to an algorithm identifier. + */ +ALG_ID MapHashAlgorithm(JNIEnv *env, jstring jHashAlgorithm) { + + const char* pszHashAlgorithm = NULL; + ALG_ID algId = 0; + + if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL)) + == NULL) { + return algId; + } + + if ((strcmp("SHA", pszHashAlgorithm) == 0) || + (strcmp("SHA1", pszHashAlgorithm) == 0) || + (strcmp("SHA-1", pszHashAlgorithm) == 0)) { + + algId = CALG_SHA1; + } else if (strcmp("SHA1+MD5", pszHashAlgorithm) == 0) { + algId = CALG_SSL3_SHAMD5; // a 36-byte concatenation of SHA-1 and MD5 + } else if (strcmp("SHA-256", pszHashAlgorithm) == 0) { + algId = CALG_SHA_256; + } else if (strcmp("SHA-384", pszHashAlgorithm) == 0) { + algId = CALG_SHA_384; + } else if (strcmp("SHA-512", pszHashAlgorithm) == 0) { + algId = CALG_SHA_512; + } else if (strcmp("MD5", pszHashAlgorithm) == 0) { + algId = CALG_MD5; + } else if (strcmp("MD2", pszHashAlgorithm) == 0) { + algId = CALG_MD2; + } + + if (pszHashAlgorithm) + env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm); + + return algId; +} + +/* + * Maps the name of a hash algorithm to a CNG Algorithm Identifier. + */ +LPCWSTR MapHashIdentifier(JNIEnv *env, jstring jHashAlgorithm) { + + const char* pszHashAlgorithm = NULL; + LPCWSTR id = NULL; + + if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL)) + == NULL) { + return id; + } + + if ((strcmp("SHA", pszHashAlgorithm) == 0) || + (strcmp("SHA1", pszHashAlgorithm) == 0) || + (strcmp("SHA-1", pszHashAlgorithm) == 0)) { + + id = BCRYPT_SHA1_ALGORITHM; + } else if (strcmp("SHA-256", pszHashAlgorithm) == 0) { + id = BCRYPT_SHA256_ALGORITHM; + } else if (strcmp("SHA-384", pszHashAlgorithm) == 0) { + id = BCRYPT_SHA384_ALGORITHM; + } else if (strcmp("SHA-512", pszHashAlgorithm) == 0) { + id = BCRYPT_SHA512_ALGORITHM; + } + + if (pszHashAlgorithm) + env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm); + + return id; +} + +/* + * Returns a certificate chain context given a certificate context and key + * usage identifier. + */ +bool GetCertificateChain(LPSTR lpszKeyUsageIdentifier, PCCERT_CONTEXT pCertContext, PCCERT_CHAIN_CONTEXT* ppChainContext) +{ + CERT_ENHKEY_USAGE EnhkeyUsage; + CERT_USAGE_MATCH CertUsage; + CERT_CHAIN_PARA ChainPara; + DWORD dwFlags = 0; + LPSTR szUsageIdentifierArray[1]; + + szUsageIdentifierArray[0] = lpszKeyUsageIdentifier; + EnhkeyUsage.cUsageIdentifier = 1; + EnhkeyUsage.rgpszUsageIdentifier = szUsageIdentifierArray; + CertUsage.dwType = USAGE_MATCH_TYPE_AND; + CertUsage.Usage = EnhkeyUsage; + ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); + ChainPara.RequestedUsage=CertUsage; + + // Build a chain using CertGetCertificateChain + // and the certificate retrieved. + return (::CertGetCertificateChain(NULL, // use the default chain engine + pCertContext, // pointer to the end certificate + NULL, // use the default time + NULL, // search no additional stores + &ChainPara, // use AND logic and enhanced key usage + // as indicated in the ChainPara + // data structure + dwFlags, + NULL, // currently reserved + ppChainContext) == TRUE); // return a pointer to the chain created +} + + +///////////////////////////////////////////////////////////////////////////// +// + +/* + * Class: sun_security_mscapi_PRNG + * Method: generateSeed + * Signature: (I[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed + (JNIEnv *env, jclass clazz, jint length, jbyteArray seed) +{ + + HCRYPTPROV hCryptProv = NULL; + jbyte* reseedBytes = NULL; + jbyte* seedBytes = NULL; + jbyteArray result = NULL; + + __try + { + // Acquire a CSP context. + if(::CryptAcquireContext( //deprecated + &hCryptProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT) == FALSE) + { + ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); + __leave; + } + + /* + * If length is negative and a seed is supplied, use it to re-seed the + * generator. Return null whether a seed is supplied or not. + * If length is non-zero then generate a new seed according to the + * requested length and return the new seed. + * If length is zero then overwrite the supplied seed with a new + * seed of the same length and return the seed. + */ + if (length < 0) { + if (seed == NULL) { + __leave; + } + length = env->GetArrayLength(seed); + if ((reseedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { + __leave; + } + + if (::CryptGenRandom( //deprecated + hCryptProv, + length, + (BYTE *) reseedBytes) == FALSE) { + + ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); + __leave; + } + + result = NULL; + + } else { + + if (length > 0) { + seed = env->NewByteArray(length); + if (seed == NULL) { + __leave; + } + } else { + length = env->GetArrayLength(seed); + } + + if ((seedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { + __leave; + } + + if (::CryptGenRandom( //deprecated + hCryptProv, + length, + (BYTE *) seedBytes) == FALSE) { + + ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); + __leave; + } + + result = seed; // seed will be updated when seedBytes gets released + } + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (reseedBytes) + env->ReleaseByteArrayElements(seed, reseedBytes, JNI_ABORT); + + if (seedBytes) + env->ReleaseByteArrayElements(seed, seedBytes, 0); // update orig + + if (hCryptProv) + ::CryptReleaseContext(hCryptProv, 0); //deprecated + } + + return result; +} + + +/* + * Class: sun_security_mscapi_CKeyStore + * Method: loadKeysOrCertificateChains + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateChains + (JNIEnv *env, jobject obj, jstring jCertStoreName) +{ + /** + * Certificate in cert store has enhanced key usage extension + * property (or EKU property) that is not part of the certificate itself. To determine + * if the certificate should be returned, both the enhanced key usage in certificate + * extension block and the extension property stored along with the certificate in + * certificate store should be examined. Otherwise, we won't be able to determine + * the proper key usage from the Java side because the information is not stored as + * part of the encoded certificate. + */ + + const char* pszCertStoreName = NULL; + HCERTSTORE hCertStore = NULL; + PCCERT_CONTEXT pCertContext = NULL; + char* pszNameString = NULL; // certificate's friendly name + DWORD cchNameString = 0; + + + __try + { + // Open a system certificate store. + if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) + == NULL) { + __leave; + } + if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) + == NULL) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Determine clazz and method ID to generate certificate + jclass clazzArrayList = env->FindClass("java/util/ArrayList"); + if (clazzArrayList == NULL) { + __leave; + } + + jmethodID mNewArrayList = env->GetMethodID(clazzArrayList, "", "()V"); + if (mNewArrayList == NULL) { + __leave; + } + + jclass clazzOfThis = env->GetObjectClass(obj); + if (clazzOfThis == NULL) { + __leave; + } + + jmethodID mGenCert = env->GetMethodID(clazzOfThis, + "generateCertificate", + "([BLjava/util/Collection;)V"); + if (mGenCert == NULL) { + __leave; + } + + // Determine method ID to generate certificate chain + jmethodID mGenCertChain = env->GetMethodID(clazzOfThis, + "generateCertificateChain", + "(Ljava/lang/String;Ljava/util/Collection;)V"); + if (mGenCertChain == NULL) { + __leave; + } + + // Determine method ID to generate RSA certificate chain + jmethodID mGenKeyAndCertChain = env->GetMethodID(clazzOfThis, + "generateKeyAndCertificateChain", + "(ZLjava/lang/String;JJILjava/util/Collection;)V"); + if (mGenKeyAndCertChain == NULL) { + __leave; + } + + // Use CertEnumCertificatesInStore to get the certificates + // from the open store. pCertContext must be reset to + // NULL to retrieve the first certificate in the store. + while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext)) + { + PP("--------------------------"); + // Check if private key available - client authentication certificate + // must have private key available. + HCRYPTPROV hCryptProv = NULL; + DWORD dwKeySpec = 0; + HCRYPTKEY hUserKey = NULL; + BOOL bCallerFreeProv = FALSE; + BOOL bHasNoPrivateKey = FALSE; + DWORD dwPublicKeyLength = 0; + + // First, probe it silently + if (::CryptAcquireCertificatePrivateKey(pCertContext, + CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG, NULL, + &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE + && GetLastError() != NTE_SILENT_CONTEXT) + { + PP("bHasNoPrivateKey = TRUE!"); + bHasNoPrivateKey = TRUE; + } + else + { + if (bCallerFreeProv == TRUE) { + ::CryptReleaseContext(hCryptProv, NULL); // deprecated + bCallerFreeProv = FALSE; + } + + // Second, acquire the key normally (not silently) + if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL, + &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE) + { + PP("bHasNoPrivateKey = TRUE!!"); + bHasNoPrivateKey = TRUE; + } + else + { + if ((dwKeySpec & CERT_NCRYPT_KEY_SPEC) == CERT_NCRYPT_KEY_SPEC) { + PP("CNG %I64d", (__int64)hCryptProv); + } else { + // Private key is available + BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey); //deprecated + + // Skip certificate if cannot find private key + if (bGetUserKey == FALSE) { + if (bCallerFreeProv) + ::CryptReleaseContext(hCryptProv, NULL); // deprecated + continue; + } + + // Set cipher mode to ECB + DWORD dwCipherMode = CRYPT_MODE_ECB; + ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL); //deprecated + PP("CAPI %I64d %I64d", (__int64)hCryptProv, (__int64)hUserKey); + } + // If the private key is present in smart card, we may not be able to + // determine the key length by using the private key handle. However, + // since public/private key pairs must have the same length, we could + // determine the key length of the private key by using the public key + // in the certificate. + dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &(pCertContext->pCertInfo->SubjectPublicKeyInfo)); + } + } + PCCERT_CHAIN_CONTEXT pCertChainContext = NULL; + + // Build certificate chain by using system certificate store. + // Add cert chain into collection for any key usage. + // + if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext)) + { + for (DWORD i = 0; i < pCertChainContext->cChain; i++) + { + // Found cert chain + PCERT_SIMPLE_CHAIN rgpChain = + pCertChainContext->rgpChain[i]; + + // Create ArrayList to store certs in each chain + jobject jArrayList = + env->NewObject(clazzArrayList, mNewArrayList); + if (jArrayList == NULL) { + __leave; + } + + // Cleanup the previous allocated name + if (pszNameString) { + delete [] pszNameString; + pszNameString = NULL; + } + + for (unsigned int j=0; j < rgpChain->cElement; j++) + { + PCERT_CHAIN_ELEMENT rgpElement = + rgpChain->rgpElement[j]; + PCCERT_CONTEXT pc = rgpElement->pCertContext; + + // Retrieve the friendly name of the first certificate + // in the chain + if (j == 0) { + + // If the cert's name cannot be retrieved then + // pszNameString remains set to NULL. + // (An alias name will be generated automatically + // when storing this cert in the keystore.) + + // Get length of friendly name + if ((cchNameString = CertGetNameString(pc, + CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, + NULL, 0)) > 1) { + + // Found friendly name + pszNameString = new (env) char[cchNameString]; + if (pszNameString == NULL) { + __leave; + } + + CertGetNameString(pc, + CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, + pszNameString, cchNameString); + } + } + + BYTE* pbCertEncoded = pc->pbCertEncoded; + DWORD cbCertEncoded = pc->cbCertEncoded; + + // Allocate and populate byte array + jbyteArray byteArray = env->NewByteArray(cbCertEncoded); + if (byteArray == NULL) { + __leave; + } + env->SetByteArrayRegion(byteArray, 0, cbCertEncoded, + (jbyte*) pbCertEncoded); + + // Generate certificate from byte array and store into + // cert collection + env->CallVoidMethod(obj, mGenCert, byteArray, jArrayList); + } + + // Usually pszNameString should be non-NULL. It's either + // the friendly name or an element from the subject name + // or SAN. + if (pszNameString) + { + PP("%s: %s", pszNameString, + pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); + if (bHasNoPrivateKey) + { + // Generate certificate chain and store into cert chain + // collection + jstring name = env->NewStringUTF(pszNameString); + if (name == NULL) { + __leave; + } + env->CallVoidMethod(obj, mGenCertChain, + name, + jArrayList); + } + else + { + if (hUserKey) { + // Only accept RSA for CAPI + DWORD dwData = CALG_RSA_KEYX; + DWORD dwSize = sizeof(DWORD); + ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData, //deprecated + &dwSize, NULL); + if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA) + { + // Generate RSA certificate chain and store into cert + // chain collection + jstring name = env->NewStringUTF(pszNameString); + if (name == NULL) { + __leave; + } + env->CallVoidMethod(obj, mGenKeyAndCertChain, + 1, + name, + (jlong) hCryptProv, (jlong) hUserKey, + dwPublicKeyLength, jArrayList); + } + } else { + // Only accept EC for CNG + BYTE buffer[32]; + DWORD len = 0; + if (::NCryptGetProperty( + hCryptProv, NCRYPT_ALGORITHM_PROPERTY, + (PBYTE)buffer, 32, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { + jstring name = env->NewStringUTF(pszNameString); + if (name == NULL) { + __leave; + } + if (buffer[0] == 'E' && buffer[2] == 'C' + && (dwPublicKeyLength == 256 + || dwPublicKeyLength == 384 + || dwPublicKeyLength == 521)) { + env->CallVoidMethod(obj, mGenKeyAndCertChain, + 0, + name, + (jlong) hCryptProv, (jlong) 0, + dwPublicKeyLength, jArrayList); + } else if (buffer[0] == 'R' && buffer[2] == 'S' + && buffer[4] == 'A') { + env->CallVoidMethod(obj, mGenKeyAndCertChain, + 1, + name, + (jlong) hCryptProv, (jlong) 0, + dwPublicKeyLength, jArrayList); + } else { + dump("Unknown NCRYPT_ALGORITHM_PROPERTY", buffer, len); + } + } + } + } + } + } + + // Free cert chain + if (pCertChainContext) + ::CertFreeCertificateChain(pCertChainContext); + } else { + PP("GetCertificateChain failed %d", GetLastError()); + } + } + } + __finally + { + if (hCertStore) + ::CertCloseStore(hCertStore, 0); + + if (pszCertStoreName) + env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); + + if (pszNameString) + delete [] pszNameString; + } +} + + +/* + * Class: sun_security_mscapi_CKey + * Method: cleanUp + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_sun_security_mscapi_CKey_cleanUp + (JNIEnv *env, jclass clazz, jlong hCryptProv, jlong hCryptKey) +{ + if (hCryptKey == NULL && hCryptProv != NULL) { + NCryptFreeObject((NCRYPT_HANDLE)hCryptProv); + } else { + if (hCryptKey != NULL) + ::CryptDestroyKey((HCRYPTKEY) hCryptKey); // deprecated + + if (hCryptProv != NULL) + ::CryptReleaseContext((HCRYPTPROV) hCryptProv, NULL); // deprecated + } +} + +/* + * Class: sun_security_mscapi_CSignature + * Method: signHash + * Signature: (Z[BILjava/lang/String;JJ)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signHash + (JNIEnv *env, jclass clazz, jboolean noHashOID, jbyteArray jHash, + jint jHashSize, jstring jHashAlgorithm, jlong hCryptProv, + jlong hCryptKey) +{ + HCRYPTHASH hHash = NULL; + jbyte* pHashBuffer = NULL; + jbyte* pSignedHashBuffer = NULL; + jbyteArray jSignedHash = NULL; + HCRYPTPROV hCryptProvAlt = NULL; + + __try + { + // Map hash algorithm + ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm); + + // Acquire a hash object handle. + if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) == FALSE) //deprecated + { + // Failover to using the PROV_RSA_AES CSP + + DWORD cbData = 256; + BYTE pbData[256]; + pbData[0] = '\0'; + + // Get name of the key container + ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER, //deprecated + (BYTE *)pbData, &cbData, 0); + + // Acquire an alternative CSP handle + if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL, //deprecated + PROV_RSA_AES, 0) == FALSE) + { + + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + + // Acquire a hash object handle. + if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0, //deprecated + &hHash) == FALSE) + { + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + } + + // Copy hash from Java to native buffer + pHashBuffer = new (env) jbyte[jHashSize]; + if (pHashBuffer == NULL) { + __leave; + } + env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); + + // Set hash value in the hash object + if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)pHashBuffer, NULL) == FALSE) //deprecated + { + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + + // Determine key spec. + DWORD dwKeySpec = AT_SIGNATURE; + ALG_ID dwAlgId; + DWORD dwAlgIdLen = sizeof(ALG_ID); + + if (! ::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) { //deprecated + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + + } + if (CALG_RSA_KEYX == dwAlgId) { + dwKeySpec = AT_KEYEXCHANGE; + } + + // Determine size of buffer + DWORD dwBufLen = 0; + DWORD dwFlags = 0; + + if (noHashOID == JNI_TRUE) { + dwFlags = CRYPT_NOHASHOID; // omit hash OID in NONEwithRSA signature + } + + if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, NULL, &dwBufLen) == FALSE) //deprecated + { + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + + pSignedHashBuffer = new (env) jbyte[dwBufLen]; + if (pSignedHashBuffer == NULL) { + __leave; + } + if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, (BYTE*)pSignedHashBuffer, &dwBufLen) == FALSE) //deprecated + { + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + + // Create new byte array + jbyteArray temp = env->NewByteArray(dwBufLen); + if (temp == NULL) { + __leave; + } + + // Copy data from native buffer + env->SetByteArrayRegion(temp, 0, dwBufLen, pSignedHashBuffer); + + jSignedHash = temp; + } + __finally + { + if (pSignedHashBuffer) + delete [] pSignedHashBuffer; + + if (pHashBuffer) + delete [] pHashBuffer; + + if (hHash) + ::CryptDestroyHash(hHash); //deprecated + + if (hCryptProvAlt) + ::CryptReleaseContext(hCryptProvAlt, 0); // deprecated + } + + return jSignedHash; +} + +/* + * Class: sun_security_mscapi_CSignature + * Method: signCngHash + * Signature: (I[BIILjava/lang/String;JJ)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signCngHash + (JNIEnv *env, jclass clazz, jint type, jbyteArray jHash, + jint jHashSize, jint saltLen, jstring jHashAlgorithm, jlong hCryptProv, + jlong hCryptKey) +{ + jbyteArray jSignedHash = NULL; + + jbyte* pHashBuffer = NULL; + jbyte* pSignedHashBuffer = NULL; + NCRYPT_KEY_HANDLE hk = NULL; + + __try + { + if (hCryptKey == 0) { + hk = (NCRYPT_KEY_HANDLE)hCryptProv; + } else { + SS_CHECK(::NCryptTranslateHandle( + NULL, + &hk, + (HCRYPTPROV)hCryptProv, + (HCRYPTKEY)hCryptKey, + NULL, + 0)); + } + + // Copy hash from Java to native buffer + pHashBuffer = new (env) jbyte[jHashSize]; + if (pHashBuffer == NULL) { + __leave; + } + env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); + + VOID* param; + DWORD dwFlags; + + switch (type) { + case 0: + param = NULL; + dwFlags = 0; + break; + case 1: + BCRYPT_PKCS1_PADDING_INFO pkcs1Info; + if (jHashAlgorithm) { + pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); + if (pkcs1Info.pszAlgId == NULL) { + ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, + "Unrecognised hash algorithm"); + __leave; + } + } else { + pkcs1Info.pszAlgId = NULL; + } + param = &pkcs1Info; + dwFlags = BCRYPT_PAD_PKCS1; + break; + case 2: + BCRYPT_PSS_PADDING_INFO pssInfo; + pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); + pssInfo.cbSalt = saltLen; + if (pssInfo.pszAlgId == NULL) { + ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, + "Unrecognised hash algorithm"); + __leave; + } + param = &pssInfo; + dwFlags = BCRYPT_PAD_PSS; + break; + } + + DWORD jSignedHashSize = 0; + SS_CHECK(::NCryptSignHash( + hk, + param, + (BYTE*)pHashBuffer, jHashSize, + NULL, 0, &jSignedHashSize, + dwFlags + )); + + pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; + if (pSignedHashBuffer == NULL) { + __leave; + } + + SS_CHECK(::NCryptSignHash( + hk, + param, + (BYTE*)pHashBuffer, jHashSize, + (BYTE*)pSignedHashBuffer, jSignedHashSize, &jSignedHashSize, + dwFlags + )); + + // Create new byte array + jbyteArray temp = env->NewByteArray(jSignedHashSize); + if (temp == NULL) { + __leave; + } + + // Copy data from native buffer + env->SetByteArrayRegion(temp, 0, jSignedHashSize, pSignedHashBuffer); + + jSignedHash = temp; + } + __finally + { + if (pSignedHashBuffer) + delete [] pSignedHashBuffer; + + if (pHashBuffer) + delete [] pHashBuffer; + + if (hCryptKey != 0 && hk != NULL) + ::NCryptFreeObject(hk); + } + + return jSignedHash; +} + +/* + * Class: sun_security_mscapi_CSignature + * Method: verifySignedHash + * Signature: ([BIL/java/lang/String;[BIJJ)Z + */ +JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifySignedHash + (JNIEnv *env, jclass clazz, jbyteArray jHash, jint jHashSize, + jstring jHashAlgorithm, jbyteArray jSignedHash, jint jSignedHashSize, + jlong hCryptProv, jlong hCryptKey) +{ + HCRYPTHASH hHash = NULL; + jbyte* pHashBuffer = NULL; + jbyte* pSignedHashBuffer = NULL; + DWORD dwSignedHashBufferLen = jSignedHashSize; + jboolean result = JNI_FALSE; + HCRYPTPROV hCryptProvAlt = NULL; + + __try + { + // Map hash algorithm + ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm); + + // Acquire a hash object handle. + if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) + == FALSE) + { + // Failover to using the PROV_RSA_AES CSP + + DWORD cbData = 256; + BYTE pbData[256]; + pbData[0] = '\0'; + + // Get name of the key container + ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER, //deprecated + (BYTE *)pbData, &cbData, 0); + + // Acquire an alternative CSP handle + if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL, //deprecated + PROV_RSA_AES, 0) == FALSE) + { + + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + + // Acquire a hash object handle. + if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0, + &hHash) == FALSE) + { + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + } + + // Copy hash and signedHash from Java to native buffer + pHashBuffer = new (env) jbyte[jHashSize]; + if (pHashBuffer == NULL) { + __leave; + } + env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); + + pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; + if (pSignedHashBuffer == NULL) { + __leave; + } + env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize, + pSignedHashBuffer); + + // Set hash value in the hash object + if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*) pHashBuffer, NULL) //deprecated + == FALSE) + { + ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); + __leave; + } + + // For RSA, the hash encryption algorithm is normally the same as the + // public key algorithm, so AT_SIGNATURE is used. + + // Verify the signature + if (::CryptVerifySignatureA(hHash, (BYTE *) pSignedHashBuffer, //deprecated + dwSignedHashBufferLen, (HCRYPTKEY) hCryptKey, NULL, 0) == TRUE) + { + result = JNI_TRUE; + } + } + + __finally + { + if (pSignedHashBuffer) + delete [] pSignedHashBuffer; + + if (pHashBuffer) + delete [] pHashBuffer; + + if (hHash) + ::CryptDestroyHash(hHash); //deprecated + + if (hCryptProvAlt) + ::CryptReleaseContext(hCryptProvAlt, 0); // deprecated + } + + return result; +} + +/* + * Class: sun_security_mscapi_CSignature + * Method: verifyCngSignedHash + * Signature: (I[BI[BIILjava/lang/String;JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifyCngSignedHash + (JNIEnv *env, jclass clazz, jint type, + jbyteArray jHash, jint jHashSize, + jbyteArray jSignedHash, jint jSignedHashSize, + jint saltLen, jstring jHashAlgorithm, + jlong hCryptProv, jlong hCryptKey) +{ + jbyte* pHashBuffer = NULL; + jbyte* pSignedHashBuffer = NULL; + jboolean result = JNI_FALSE; + NCRYPT_KEY_HANDLE hk = NULL; + + __try + { + if (hCryptKey == 0) { + hk = (NCRYPT_KEY_HANDLE)hCryptProv; + } else { + SS_CHECK(::NCryptTranslateHandle( + NULL, + &hk, + (HCRYPTPROV)hCryptProv, + (HCRYPTKEY)hCryptKey, + NULL, + 0)); + } + + // Copy hash and signedHash from Java to native buffer + pHashBuffer = new (env) jbyte[jHashSize]; + if (pHashBuffer == NULL) { + __leave; + } + env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); + + pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; + if (pSignedHashBuffer == NULL) { + __leave; + } + env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize, + pSignedHashBuffer); + + VOID* param; + DWORD dwFlags; + + switch (type) { + case 0: + param = NULL; + dwFlags = 0; + break; + case 1: + BCRYPT_PKCS1_PADDING_INFO pkcs1Info; + if (jHashAlgorithm) { + pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); + if (pkcs1Info.pszAlgId == NULL) { + ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, + "Unrecognised hash algorithm"); + __leave; + } + } else { + pkcs1Info.pszAlgId = NULL; + } + param = &pkcs1Info; + dwFlags = NCRYPT_PAD_PKCS1_FLAG; + break; + case 2: + BCRYPT_PSS_PADDING_INFO pssInfo; + pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm); + pssInfo.cbSalt = saltLen; + if (pssInfo.pszAlgId == NULL) { + ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION, + "Unrecognised hash algorithm"); + __leave; + } + param = &pssInfo; + dwFlags = NCRYPT_PAD_PSS_FLAG; + break; + } + + if (::NCryptVerifySignature(hk, param, + (BYTE *) pHashBuffer, jHashSize, + (BYTE *) pSignedHashBuffer, jSignedHashSize, + dwFlags) == ERROR_SUCCESS) + { + result = JNI_TRUE; + } + } + + __finally + { + if (pSignedHashBuffer) + delete [] pSignedHashBuffer; + + if (pHashBuffer) + delete [] pHashBuffer; + + if (hCryptKey != 0 && hk != NULL) + ::NCryptFreeObject(hk); + } + + return result; +} + +#define DUMP_PROP(p) \ + if (::NCryptGetProperty(hKey, p, (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { \ + sprintf(header, "%s %ls", #p, p); \ + dump(header, buffer, len); \ + } + +#define EXPORT_BLOB(p) \ + desc.cBuffers = 0; \ + if (::NCryptExportKey(hKey, NULL, p, &desc, (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { \ + sprintf(header, "%s %ls (%ld)", #p, p, desc.cBuffers); \ + dump(header, buffer, len); \ + for (int i = 0; i < (int)desc.cBuffers; i++) { \ + sprintf(header, "desc %ld", desc.pBuffers[i].BufferType); \ + dump(header, (PBYTE)desc.pBuffers[i].pvBuffer, desc.pBuffers[i].cbBuffer); \ + } \ + } + +void showProperty(NCRYPT_HANDLE hKey) { + char header[100]; + BYTE buffer[8192]; + DWORD len = 9; + NCryptBufferDesc desc; + DUMP_PROP(NCRYPT_ALGORITHM_GROUP_PROPERTY); + DUMP_PROP(NCRYPT_ALGORITHM_PROPERTY); + DUMP_PROP(NCRYPT_ASSOCIATED_ECDH_KEY); + DUMP_PROP(NCRYPT_BLOCK_LENGTH_PROPERTY); + DUMP_PROP(NCRYPT_CERTIFICATE_PROPERTY); + DUMP_PROP(NCRYPT_DH_PARAMETERS_PROPERTY); + DUMP_PROP(NCRYPT_EXPORT_POLICY_PROPERTY); + DUMP_PROP(NCRYPT_IMPL_TYPE_PROPERTY); + DUMP_PROP(NCRYPT_KEY_TYPE_PROPERTY); + DUMP_PROP(NCRYPT_KEY_USAGE_PROPERTY); + DUMP_PROP(NCRYPT_LAST_MODIFIED_PROPERTY); + DUMP_PROP(NCRYPT_LENGTH_PROPERTY); + DUMP_PROP(NCRYPT_LENGTHS_PROPERTY); + DUMP_PROP(NCRYPT_MAX_NAME_LENGTH_PROPERTY); + DUMP_PROP(NCRYPT_NAME_PROPERTY); + DUMP_PROP(NCRYPT_PIN_PROMPT_PROPERTY); + DUMP_PROP(NCRYPT_PIN_PROPERTY); + DUMP_PROP(NCRYPT_PROVIDER_HANDLE_PROPERTY); + DUMP_PROP(NCRYPT_READER_PROPERTY); + DUMP_PROP(NCRYPT_ROOT_CERTSTORE_PROPERTY); + DUMP_PROP(NCRYPT_SCARD_PIN_ID); + DUMP_PROP(NCRYPT_SCARD_PIN_INFO); + DUMP_PROP(NCRYPT_SECURE_PIN_PROPERTY); + DUMP_PROP(NCRYPT_SECURITY_DESCR_PROPERTY); + DUMP_PROP(NCRYPT_SECURITY_DESCR_SUPPORT_PROPERTY); + DUMP_PROP(NCRYPT_SMARTCARD_GUID_PROPERTY); + DUMP_PROP(NCRYPT_UI_POLICY_PROPERTY); + DUMP_PROP(NCRYPT_UNIQUE_NAME_PROPERTY); + DUMP_PROP(NCRYPT_USE_CONTEXT_PROPERTY); + DUMP_PROP(NCRYPT_USE_COUNT_ENABLED_PROPERTY); + DUMP_PROP(NCRYPT_USE_COUNT_PROPERTY); + DUMP_PROP(NCRYPT_USER_CERTSTORE_PROPERTY); + DUMP_PROP(NCRYPT_VERSION_PROPERTY); + DUMP_PROP(NCRYPT_WINDOW_HANDLE_PROPERTY); + + EXPORT_BLOB(BCRYPT_DH_PRIVATE_BLOB); + EXPORT_BLOB(BCRYPT_DH_PUBLIC_BLOB); + EXPORT_BLOB(BCRYPT_DSA_PRIVATE_BLOB); + EXPORT_BLOB(BCRYPT_DSA_PUBLIC_BLOB); + EXPORT_BLOB(BCRYPT_ECCPRIVATE_BLOB); + EXPORT_BLOB(BCRYPT_ECCPUBLIC_BLOB); + EXPORT_BLOB(BCRYPT_PUBLIC_KEY_BLOB); + EXPORT_BLOB(BCRYPT_PRIVATE_KEY_BLOB); + EXPORT_BLOB(BCRYPT_RSAFULLPRIVATE_BLOB); + EXPORT_BLOB(BCRYPT_RSAPRIVATE_BLOB); + EXPORT_BLOB(BCRYPT_RSAPUBLIC_BLOB); + EXPORT_BLOB(LEGACY_DH_PRIVATE_BLOB); + EXPORT_BLOB(LEGACY_DH_PUBLIC_BLOB); + EXPORT_BLOB(LEGACY_DSA_PRIVATE_BLOB); + EXPORT_BLOB(LEGACY_DSA_PUBLIC_BLOB); + EXPORT_BLOB(LEGACY_RSAPRIVATE_BLOB); + EXPORT_BLOB(LEGACY_RSAPUBLIC_BLOB); + // Support starts from Windows 8 and Windows Server 2012 + //EXPORT_BLOB(NCRYPT_CIPHER_KEY_BLOB); + EXPORT_BLOB(NCRYPT_OPAQUETRANSPORT_BLOB); + EXPORT_BLOB(NCRYPT_PKCS7_ENVELOPE_BLOB); + //EXPORT_BLOB(NCRYPTBUFFER_CERT_BLOB); + //EXPORT_BLOB(NCRYPT_PKCS8_PRIVATE_KEY_BLOB); + BCryptBuffer bb; + bb.BufferType = NCRYPTBUFFER_PKCS_SECRET; + bb.cbBuffer = 18; + bb.pvBuffer = (PVOID)L"changeit"; + BCryptBufferDesc bbd; + bbd.ulVersion = 0; + bbd.cBuffers = 1; + bbd.pBuffers = &bb; + if(::NCryptExportKey(hKey, NULL, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, + (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { + sprintf(header, "NCRYPT_PKCS8_PRIVATE_KEY_BLOB %ls", NCRYPT_PKCS8_PRIVATE_KEY_BLOB); + dump(header, buffer, len); + } + // Support starts from Windows 8 and Windows Server 2012 + //EXPORT_BLOB(NCRYPT_PROTECTED_KEY_BLOB); +} + +/* + * Class: sun_security_mscapi_CKeyPairGenerator_RSA + * Method: generateCKeyPair + * Signature: (Ljava/lang/String;ILjava/lang/String;)Lsun/security/mscapi/CKeyPair; + */ +JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyPairGenerator_00024RSA_generateCKeyPair + (JNIEnv *env, jclass clazz, jstring alg, jint keySize, jstring keyContainerName) +{ + HCRYPTPROV hCryptProv = NULL; + HCRYPTKEY hKeyPair; + DWORD dwFlags = (keySize << 16) | CRYPT_EXPORTABLE; + jobject keypair = NULL; + const char* pszKeyContainerName = NULL; // UUID + + __try + { + if ((pszKeyContainerName = + env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { + __leave; + } + + // Acquire a CSP context (create a new key container). + // Prefer a PROV_RSA_AES CSP, when available, due to its support + // for SHA-2-based signatures. + if (::CryptAcquireContext( //deprecated + &hCryptProv, + pszKeyContainerName, + NULL, + PROV_RSA_AES, + CRYPT_NEWKEYSET) == FALSE) + { + // Failover to using the default CSP (PROV_RSA_FULL) + + if (::CryptAcquireContext( //deprecated + &hCryptProv, + pszKeyContainerName, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET) == FALSE) + { + ThrowException(env, KEY_EXCEPTION, GetLastError()); + __leave; + } + } + + // Generate an keypair + if(::CryptGenKey( //deprecated + hCryptProv, + AT_KEYEXCHANGE, + dwFlags, + &hKeyPair) == FALSE) + { + ThrowException(env, KEY_EXCEPTION, GetLastError()); + __leave; + } + + // Get the method ID for the CKeyPair constructor + jclass clazzCKeyPair = + env->FindClass("sun/security/mscapi/CKeyPair"); + if (clazzCKeyPair == NULL) { + __leave; + } + + jmethodID mNewCKeyPair = + env->GetMethodID(clazzCKeyPair, "", "(Ljava/lang/String;JJI)V"); + if (mNewCKeyPair == NULL) { + __leave; + } + + // Create a new keypair + keypair = env->NewObject(clazzCKeyPair, mNewCKeyPair, + alg, (jlong) hCryptProv, (jlong) hKeyPair, keySize); + + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (pszKeyContainerName) + env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); + } + + return keypair; +} + +/* + * Class: sun_security_mscapi_CKey + * Method: getContainerName + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_sun_security_mscapi_CKey_getContainerName + (JNIEnv *env, jclass jclazz, jlong hCryptProv) +{ + DWORD cbData = 256; + BYTE pbData[256]; + pbData[0] = '\0'; + + ::CryptGetProvParam( //deprecated + (HCRYPTPROV)hCryptProv, + PP_CONTAINER, + (BYTE *)pbData, + &cbData, + 0); + + return env->NewStringUTF((const char*)pbData); +} + +/* + * Class: sun_security_mscapi_CKey + * Method: getKeyType + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_sun_security_mscapi_CKey_getKeyType + (JNIEnv *env, jclass jclazz, jlong hCryptKey) +{ + ALG_ID dwAlgId; + DWORD dwAlgIdLen = sizeof(ALG_ID); + + if (::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) { //deprecated + + if (CALG_RSA_SIGN == dwAlgId) { + return env->NewStringUTF("Signature"); + + } else if (CALG_RSA_KEYX == dwAlgId) { + return env->NewStringUTF("Exchange"); + + } else { + char buffer[64]; + if (sprintf(buffer, "%lu", dwAlgId)) { + return env->NewStringUTF(buffer); + } + } + } + + return env->NewStringUTF(""); +} + +/* + * Class: sun_security_mscapi_CKeyStore + * Method: storeCertificate + * Signature: (Ljava/lang/String;Ljava/lang/String;[BIJJ)V + */ +JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_storeCertificate + (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName, + jbyteArray jCertEncoding, jint jCertEncodingSize, jlong hCryptProv, + jlong hCryptKey) +{ + const char* pszCertStoreName = NULL; + HCERTSTORE hCertStore = NULL; + PCCERT_CONTEXT pCertContext = NULL; + PWCHAR pszCertAliasName = NULL; + jbyte* pbCertEncoding = NULL; + const jchar* jCertAliasChars = NULL; + const char* pszContainerName = NULL; + const char* pszProviderName = NULL; + WCHAR * pwszContainerName = NULL; + WCHAR * pwszProviderName = NULL; + + __try + { + // Open a system certificate store. + if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) + == NULL) { + __leave; + } + if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Copy encoding from Java to native buffer + pbCertEncoding = new (env) jbyte[jCertEncodingSize]; + if (pbCertEncoding == NULL) { + __leave; + } + env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding); + + // Create a certificate context from the encoded cert + if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING, + (BYTE*) pbCertEncoding, jCertEncodingSize))) { + + ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError()); + __leave; + } + + // Set the certificate's friendly name + int size = env->GetStringLength(jCertAliasName); + pszCertAliasName = new (env) WCHAR[size + 1]; + if (pszCertAliasName == NULL) { + __leave; + } + + jCertAliasChars = env->GetStringChars(jCertAliasName, NULL); + if (jCertAliasChars == NULL) { + __leave; + } + memcpy(pszCertAliasName, jCertAliasChars, size * sizeof(WCHAR)); + pszCertAliasName[size] = 0; // append the string terminator + + CRYPT_DATA_BLOB friendlyName = { + sizeof(WCHAR) * (size + 1), + (BYTE *) pszCertAliasName + }; + + env->ReleaseStringChars(jCertAliasName, jCertAliasChars); + + if (! ::CertSetCertificateContextProperty(pCertContext, + CERT_FRIENDLY_NAME_PROP_ID, 0, &friendlyName)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Attach the certificate's private key (if supplied) + if (hCryptProv != 0 && hCryptKey != 0) { + + CRYPT_KEY_PROV_INFO keyProviderInfo; + DWORD dwDataLen; + + // Get the name of the key container + if (! ::CryptGetProvParam( //deprecated + (HCRYPTPROV) hCryptProv, + PP_CONTAINER, + NULL, + &dwDataLen, + 0)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + pszContainerName = new (env) char[dwDataLen]; + if (pszContainerName == NULL) { + __leave; + } + + if (! ::CryptGetProvParam( //deprecated + (HCRYPTPROV) hCryptProv, + PP_CONTAINER, + (BYTE *) pszContainerName, + &dwDataLen, + 0)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Convert to a wide char string + pwszContainerName = new (env) WCHAR[dwDataLen]; + if (pwszContainerName == NULL) { + __leave; + } + + if (mbstowcs(pwszContainerName, pszContainerName, dwDataLen) == 0) { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Set the name of the key container + keyProviderInfo.pwszContainerName = pwszContainerName; + + + // Get the name of the provider + if (! ::CryptGetProvParam( //deprecated + (HCRYPTPROV) hCryptProv, + PP_NAME, + NULL, + &dwDataLen, + 0)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + pszProviderName = new (env) char[dwDataLen]; + if (pszProviderName == NULL) { + __leave; + } + + if (! ::CryptGetProvParam( //deprecated + (HCRYPTPROV) hCryptProv, + PP_NAME, + (BYTE *) pszProviderName, + &dwDataLen, + 0)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Convert to a wide char string + pwszProviderName = new (env) WCHAR[dwDataLen]; + if (pwszProviderName == NULL) { + __leave; + } + + if (mbstowcs(pwszProviderName, pszProviderName, dwDataLen) == 0) { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Set the name of the provider + keyProviderInfo.pwszProvName = pwszProviderName; + + // Get and set the type of the provider + if (! ::CryptGetProvParam( //deprecated + (HCRYPTPROV) hCryptProv, + PP_PROVTYPE, + (LPBYTE) &keyProviderInfo.dwProvType, + &dwDataLen, + 0)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Set no provider flags + keyProviderInfo.dwFlags = 0; + + // Set no provider parameters + keyProviderInfo.cProvParam = 0; + keyProviderInfo.rgProvParam = NULL; + + // Get the key's algorithm ID + if (! ::CryptGetKeyParam( //deprecated + (HCRYPTKEY) hCryptKey, + KP_ALGID, + (LPBYTE) &keyProviderInfo.dwKeySpec, + &dwDataLen, + 0)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + // Set the key spec (using the algorithm ID). + switch (keyProviderInfo.dwKeySpec) { + case CALG_RSA_KEYX: + case CALG_DH_SF: + keyProviderInfo.dwKeySpec = AT_KEYEXCHANGE; + break; + + case CALG_RSA_SIGN: + case CALG_DSS_SIGN: + keyProviderInfo.dwKeySpec = AT_SIGNATURE; + break; + + default: + ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_ALGID); + __leave; + } + + if (! ::CertSetCertificateContextProperty(pCertContext, + CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProviderInfo)) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + } + + // Import encoded certificate + if (!::CertAddCertificateContextToStore(hCertStore, pCertContext, + CERT_STORE_ADD_REPLACE_EXISTING, NULL)) + { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (hCertStore) + ::CertCloseStore(hCertStore, 0); + + if (pszCertStoreName) + env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); + + if (pbCertEncoding) + delete [] pbCertEncoding; + + if (pszCertAliasName) + delete [] pszCertAliasName; + + if (pszContainerName) + delete [] pszContainerName; + + if (pwszContainerName) + delete [] pwszContainerName; + + if (pszProviderName) + delete [] pszProviderName; + + if (pwszProviderName) + delete [] pwszProviderName; + + if (pCertContext) + ::CertFreeCertificateContext(pCertContext); + } +} + +/* + * Class: sun_security_mscapi_CKeyStore + * Method: removeCertificate + * Signature: (Ljava/lang/String;Ljava/lang/String;[BI)V + */ +JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_removeCertificate + (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName, + jbyteArray jCertEncoding, jint jCertEncodingSize) { + + const char* pszCertStoreName = NULL; + const char* pszCertAliasName = NULL; + HCERTSTORE hCertStore = NULL; + PCCERT_CONTEXT pCertContext = NULL; + PCCERT_CONTEXT pTBDCertContext = NULL; + jbyte* pbCertEncoding = NULL; + DWORD cchNameString = 0; + char* pszNameString = NULL; // certificate's friendly name + BOOL bDeleteAttempted = FALSE; + + __try + { + // Open a system certificate store. + if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) + == NULL) { + __leave; + } + if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Copy encoding from Java to native buffer + pbCertEncoding = new (env) jbyte[jCertEncodingSize]; + if (pbCertEncoding == NULL) { + __leave; + } + env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding); + + // Create a certificate context from the encoded cert + if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING, + (BYTE*) pbCertEncoding, jCertEncodingSize))) { + + ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError()); + __leave; + } + + // Find the certificate to be deleted + if (!(pTBDCertContext = ::CertFindCertificateInStore(hCertStore, + X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext, NULL))) { + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Check that its friendly name matches the supplied alias + if ((cchNameString = ::CertGetNameString(pTBDCertContext, + CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, NULL, 0)) > 1) { + + pszNameString = new (env) char[cchNameString]; + if (pszNameString == NULL) { + __leave; + } + + ::CertGetNameString(pTBDCertContext, + CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszNameString, + cchNameString); + + // Compare the certificate's friendly name with supplied alias name + if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL)) + == NULL) { + __leave; + } + if (strcmp(pszCertAliasName, pszNameString) == 0) { + + // Only delete the certificate if the alias names matches + if (! ::CertDeleteCertificateFromStore(pTBDCertContext)) { + + // pTBDCertContext is always freed by the + // CertDeleteCertificateFromStore method + bDeleteAttempted = TRUE; + + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + } + } + + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (hCertStore) + ::CertCloseStore(hCertStore, 0); + + if (pszCertStoreName) + env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); + + if (pszCertAliasName) + env->ReleaseStringUTFChars(jCertAliasName, pszCertAliasName); + + if (pbCertEncoding) + delete [] pbCertEncoding; + + if (pszNameString) + delete [] pszNameString; + + if (pCertContext) + ::CertFreeCertificateContext(pCertContext); + + if (bDeleteAttempted && pTBDCertContext) + ::CertFreeCertificateContext(pTBDCertContext); + } +} + +/* + * Class: sun_security_mscapi_CKeyStore + * Method: destroyKeyContainer + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_destroyKeyContainer + (JNIEnv *env, jobject clazz, jstring keyContainerName) +{ + HCRYPTPROV hCryptProv = NULL; + const char* pszKeyContainerName = NULL; + + __try + { + if ((pszKeyContainerName = + env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { + __leave; + } + + // Destroying the default key container is not permitted + // (because it may contain more one keypair). + if (pszKeyContainerName == NULL) { + + ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_KEYSET_PARAM); + __leave; + } + + // Acquire a CSP context (to the key container). + if (::CryptAcquireContext( //deprecated + &hCryptProv, + pszKeyContainerName, + NULL, + PROV_RSA_FULL, + CRYPT_DELETEKEYSET) == FALSE) + { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (pszKeyContainerName) + env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); + } +} + +/* + * Class: sun_security_mscapi_CRSACipher + * Method: encryptDecrypt + * Signature: ([BIJZ)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt + (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey, + jboolean doEncrypt) +{ + jbyteArray result = NULL; + jbyte* pData = NULL; + DWORD dwDataLen = jDataSize; + DWORD dwBufLen = env->GetArrayLength(jData); + DWORD i; + BYTE tmp; + + __try + { + // Copy data from Java buffer to native buffer + pData = new (env) jbyte[dwBufLen]; + if (pData == NULL) { + __leave; + } + env->GetByteArrayRegion(jData, 0, dwBufLen, pData); + + if (doEncrypt == JNI_TRUE) { + // encrypt + if (! ::CryptEncrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated + &dwDataLen, dwBufLen)) { + + ThrowException(env, KEY_EXCEPTION, GetLastError()); + __leave; + } + dwBufLen = dwDataLen; + + // convert from little-endian + for (i = 0; i < dwBufLen / 2; i++) { + tmp = pData[i]; + pData[i] = pData[dwBufLen - i -1]; + pData[dwBufLen - i - 1] = tmp; + } + } else { + // convert to little-endian + for (i = 0; i < dwBufLen / 2; i++) { + tmp = pData[i]; + pData[i] = pData[dwBufLen - i -1]; + pData[dwBufLen - i - 1] = tmp; + } + + // decrypt + if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated + &dwBufLen)) { + + ThrowException(env, KEY_EXCEPTION, GetLastError()); + __leave; + } + } + + // Create new byte array + if ((result = env->NewByteArray(dwBufLen)) == NULL) { + __leave; + } + + // Copy data from native buffer to Java buffer + env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData); + } + __finally + { + if (pData) + delete [] pData; + } + + return result; +} + +/* + * Class: sun_security_mscapi_CPublicKey + * Method: getPublicKeyBlob + * Signature: (JJ)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_getPublicKeyBlob + (JNIEnv *env, jobject clazz, jlong hCryptProv, jlong hCryptKey) { + + jbyteArray blob = NULL; + DWORD dwBlobLen; + BYTE* pbKeyBlob = NULL; + + __try + { + + // Determine the size of the blob + if (hCryptKey == 0) { + SS_CHECK(::NCryptExportKey( + (NCRYPT_KEY_HANDLE)hCryptProv, NULL, BCRYPT_ECCPUBLIC_BLOB, + NULL, NULL, 0, &dwBlobLen, NCRYPT_SILENT_FLAG)); + } else { + if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, NULL, //deprecated + &dwBlobLen)) { + + ThrowException(env, KEY_EXCEPTION, GetLastError()); + __leave; + } + } + + pbKeyBlob = new (env) BYTE[dwBlobLen]; + if (pbKeyBlob == NULL) { + __leave; + } + + // Generate key blob + if (hCryptKey == 0) { + SS_CHECK(::NCryptExportKey( + (NCRYPT_KEY_HANDLE)hCryptProv, NULL, BCRYPT_ECCPUBLIC_BLOB, + NULL, pbKeyBlob, dwBlobLen, &dwBlobLen, NCRYPT_SILENT_FLAG)); + } else { + if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, //deprecated + pbKeyBlob, &dwBlobLen)) { + + ThrowException(env, KEY_EXCEPTION, GetLastError()); + __leave; + } + } + + // Create new byte array + if ((blob = env->NewByteArray(dwBlobLen)) == NULL) { + __leave; + } + + // Copy data from native buffer to Java buffer + env->SetByteArrayRegion(blob, 0, dwBlobLen, (jbyte*) pbKeyBlob); + } + __finally + { + if (pbKeyBlob) + delete [] pbKeyBlob; + } + + return blob; +} + +/* + * Class: sun_security_mscapi_CPublicKey_CRSAPublicKey + * Method: getExponent + * Signature: ([B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_00024CRSAPublicKey_getExponent + (JNIEnv *env, jobject clazz, jbyteArray jKeyBlob) { + + jbyteArray exponent = NULL; + jbyte* exponentBytes = NULL; + jbyte* keyBlob = NULL; + + __try { + + jsize length = env->GetArrayLength(jKeyBlob); + jsize headerLength = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); + + if (length < headerLength) { + ThrowExceptionWithMessage(env, KEY_EXCEPTION, "Invalid BLOB"); + __leave; + } + + if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) { + __leave; + } + + PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob; + + // Check BLOB type + if (pPublicKeyStruc->bType != PUBLICKEYBLOB) { + ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE); + __leave; + } + + RSAPUBKEY* pRsaPubKey = + (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC)); + + int len = sizeof(pRsaPubKey->pubexp); + exponentBytes = new (env) jbyte[len]; + if (exponentBytes == NULL) { + __leave; + } + + // convert from little-endian while copying from blob + for (int i = 0, j = len - 1; i < len; i++, j--) { + exponentBytes[i] = ((BYTE*) &pRsaPubKey->pubexp)[j]; + } + + if ((exponent = env->NewByteArray(len)) == NULL) { + __leave; + } + env->SetByteArrayRegion(exponent, 0, len, exponentBytes); + } + __finally + { + if (keyBlob) + env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT); + + if (exponentBytes) + delete [] exponentBytes; + } + + return exponent; +} + +/* + * Class: sun_security_mscapi_CPublicKey_CRSAPublicKey + * Method: getModulus + * Signature: ([B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_00024CRSAPublicKey_getModulus + (JNIEnv *env, jobject clazz, jbyteArray jKeyBlob) { + + jbyteArray modulus = NULL; + jbyte* modulusBytes = NULL; + jbyte* keyBlob = NULL; + + __try { + + jsize length = env->GetArrayLength(jKeyBlob); + jsize headerLength = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); + + if (length < headerLength) { + ThrowExceptionWithMessage(env, KEY_EXCEPTION, "Invalid BLOB"); + __leave; + } + + if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) { + __leave; + } + + PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob; + + // Check BLOB type + if (pPublicKeyStruc->bType != PUBLICKEYBLOB) { + ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE); + __leave; + } + + RSAPUBKEY* pRsaPubKey = + (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC)); + + int len = pRsaPubKey->bitlen / 8; + if (len < 0 || len > length - headerLength) { + ThrowExceptionWithMessage(env, KEY_EXCEPTION, "Invalid key length"); + __leave; + } + + modulusBytes = new (env) jbyte[len]; + if (modulusBytes == NULL) { + __leave; + } + BYTE * pbModulus = (BYTE *) (keyBlob + headerLength); + + // convert from little-endian while copying from blob + for (int i = 0, j = len - 1; i < len; i++, j--) { + modulusBytes[i] = pbModulus[j]; + } + + if ((modulus = env->NewByteArray(len)) == NULL) { + __leave; + } + env->SetByteArrayRegion(modulus, 0, len, modulusBytes); + } + __finally + { + if (keyBlob) + env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT); + + if (modulusBytes) + delete [] modulusBytes; + } + + return modulus; +} + +/* + * Convert an array in big-endian byte order into little-endian byte order. + */ +int convertToLittleEndian(JNIEnv *env, jbyteArray source, jbyte* destination, + int destinationLength) { + + int result = -1; + jbyte* sourceBytes = NULL; + + __try { + int sourceLength = env->GetArrayLength(source); + + sourceBytes = env->GetByteArrayElements(source, 0); + if (sourceBytes == NULL) { + __leave; + } + + int copyLen = sourceLength; + if (sourceLength > destinationLength) { + // source might include an extra sign byte + if (sourceLength == destinationLength + 1 && sourceBytes[0] == 0) { + copyLen--; + } else { + __leave; + } + } + + // Copy bytes from the end of the source array to the beginning of the + // destination array (until the destination array is full). + // This ensures that the sign byte from the source array will be excluded. + for (int i = 0; i < copyLen; i++) { + destination[i] = sourceBytes[sourceLength - 1 - i]; + } + if (copyLen < destinationLength) { + memset(destination + copyLen, 0, destinationLength - copyLen); + } + result = destinationLength; + } __finally { + // Clean up. + if (sourceBytes) { + env->ReleaseByteArrayElements(source, sourceBytes, JNI_ABORT); + } + } + + return result; +} + +/* + * The Microsoft Base Cryptographic Provider supports public-key BLOBs + * that have the following format: + * + * PUBLICKEYSTRUC publickeystruc; + * RSAPUBKEY rsapubkey; + * BYTE modulus[rsapubkey.bitlen/8]; + * + * and private-key BLOBs that have the following format: + * + * PUBLICKEYSTRUC publickeystruc; + * RSAPUBKEY rsapubkey; + * BYTE modulus[rsapubkey.bitlen/8]; + * BYTE prime1[rsapubkey.bitlen/16]; + * BYTE prime2[rsapubkey.bitlen/16]; + * BYTE exponent1[rsapubkey.bitlen/16]; + * BYTE exponent2[rsapubkey.bitlen/16]; + * BYTE coefficient[rsapubkey.bitlen/16]; + * BYTE privateExponent[rsapubkey.bitlen/8]; + * + * This method generates such BLOBs from the key elements supplied. + */ +jbyteArray generateKeyBlob( + JNIEnv *env, + jint jKeyBitLength, + jbyteArray jModulus, + jbyteArray jPublicExponent, + jbyteArray jPrivateExponent, + jbyteArray jPrimeP, + jbyteArray jPrimeQ, + jbyteArray jExponentP, + jbyteArray jExponentQ, + jbyteArray jCrtCoefficient) +{ + jsize jKeyByteLength = jKeyBitLength / 8; + jsize jBlobLength; + BOOL bGeneratePrivateKeyBlob; + + // Determine whether to generate a public-key or a private-key BLOB + if (jPrivateExponent != NULL && + jPrimeP != NULL && + jPrimeQ != NULL && + jExponentP != NULL && + jExponentQ != NULL && + jCrtCoefficient != NULL) { + + bGeneratePrivateKeyBlob = TRUE; + jBlobLength = sizeof(BLOBHEADER) + + sizeof(RSAPUBKEY) + + ((jKeyBitLength / 8) * 4) + + (jKeyBitLength / 16); + + } else { + bGeneratePrivateKeyBlob = FALSE; + jBlobLength = sizeof(BLOBHEADER) + + sizeof(RSAPUBKEY) + + (jKeyBitLength / 8); + } + + jbyte* jBlobBytes = NULL; + jbyte* jBlobElement; + jbyteArray jBlob = NULL; + jsize jElementLength; + + __try { + jBlobBytes = new (env) jbyte[jBlobLength]; + if (jBlobBytes == NULL) { + __leave; + } + + BLOBHEADER *pBlobHeader = (BLOBHEADER *) jBlobBytes; + if (bGeneratePrivateKeyBlob) { + pBlobHeader->bType = PRIVATEKEYBLOB; // 0x07 + } else { + pBlobHeader->bType = PUBLICKEYBLOB; // 0x06 + } + pBlobHeader->bVersion = CUR_BLOB_VERSION; // 0x02 + pBlobHeader->reserved = 0; // 0x0000 + pBlobHeader->aiKeyAlg = CALG_RSA_KEYX; // 0x0000a400 + + RSAPUBKEY *pRsaPubKey = + (RSAPUBKEY *) (jBlobBytes + sizeof(PUBLICKEYSTRUC)); + if (bGeneratePrivateKeyBlob) { + pRsaPubKey->magic = 0x32415352; // "RSA2" + } else { + pRsaPubKey->magic = 0x31415352; // "RSA1" + } + pRsaPubKey->bitlen = jKeyBitLength; + pRsaPubKey->pubexp = 0; // init + + // Sanity check + jsize jPublicExponentLength = env->GetArrayLength(jPublicExponent); + if (jPublicExponentLength > sizeof(pRsaPubKey->pubexp)) { + ThrowException(env, INVALID_KEY_EXCEPTION, NTE_BAD_TYPE); + __leave; + } + // The length argument must be the smaller of jPublicExponentLength + // and sizeof(pRsaPubKey->pubkey) + if ((jElementLength = convertToLittleEndian(env, jPublicExponent, + (jbyte *) &(pRsaPubKey->pubexp), jPublicExponentLength)) < 0) { + __leave; + } + + // Modulus n + jBlobElement = + (jbyte *) (jBlobBytes + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); + if ((jElementLength = convertToLittleEndian(env, jModulus, jBlobElement, + jKeyByteLength)) < 0) { + __leave; + } + + if (bGeneratePrivateKeyBlob) { + // Prime p + jBlobElement += jElementLength; + if ((jElementLength = convertToLittleEndian(env, jPrimeP, + jBlobElement, jKeyByteLength / 2)) < 0) { + __leave; + } + + // Prime q + jBlobElement += jElementLength; + if ((jElementLength = convertToLittleEndian(env, jPrimeQ, + jBlobElement, jKeyByteLength / 2)) < 0) { + __leave; + } + + // Prime exponent p + jBlobElement += jElementLength; + if ((jElementLength = convertToLittleEndian(env, jExponentP, + jBlobElement, jKeyByteLength / 2)) < 0) { + __leave; + } + + // Prime exponent q + jBlobElement += jElementLength; + if ((jElementLength = convertToLittleEndian(env, jExponentQ, + jBlobElement, jKeyByteLength / 2)) < 0) { + __leave; + } + + // CRT coefficient + jBlobElement += jElementLength; + if ((jElementLength = convertToLittleEndian(env, jCrtCoefficient, + jBlobElement, jKeyByteLength / 2)) < 0) { + __leave; + } + + // Private exponent + jBlobElement += jElementLength; + if ((jElementLength = convertToLittleEndian(env, jPrivateExponent, + jBlobElement, jKeyByteLength)) < 0) { + __leave; + } + } + + if ((jBlob = env->NewByteArray(jBlobLength)) == NULL) { + __leave; + } + env->SetByteArrayRegion(jBlob, 0, jBlobLength, jBlobBytes); + + } + __finally + { + if (jBlobBytes) + delete [] jBlobBytes; + } + + return jBlob; +} + +/* + * Class: sun_security_mscapi_CKeyStore + * Method: generateRSAPrivateKeyBlob + * Signature: (I[B[B[B[B[B[B[B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CKeyStore_generateRSAPrivateKeyBlob + (JNIEnv *env, jobject clazz, + jint jKeyBitLength, + jbyteArray jModulus, + jbyteArray jPublicExponent, + jbyteArray jPrivateExponent, + jbyteArray jPrimeP, + jbyteArray jPrimeQ, + jbyteArray jExponentP, + jbyteArray jExponentQ, + jbyteArray jCrtCoefficient) +{ + return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent, + jPrivateExponent, jPrimeP, jPrimeQ, jExponentP, jExponentQ, + jCrtCoefficient); +} + +/* + * Class: sun_security_mscapi_CSignature_RSA + * Method: generatePublicKeyBlob + * Signature: (I[B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_00024RSA_generatePublicKeyBlob + (JNIEnv *env, jclass clazz, + jint jKeyBitLength, + jbyteArray jModulus, + jbyteArray jPublicExponent) +{ + return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent, + NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Class: sun_security_mscapi_CKeyStore + * Method: storePrivateKey + * Signature: (Ljava/lang/String;[BLjava/lang/String;I)Lsun/security/mscapi/CPrivateKey; + */ +JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyStore_storePrivateKey + (JNIEnv *env, jobject clazz, jstring alg, jbyteArray keyBlob, + jstring keyContainerName, jint keySize) +{ + HCRYPTPROV hCryptProv = NULL; + HCRYPTKEY hKey = NULL; + DWORD dwBlobLen; + BYTE * pbKeyBlob = NULL; + const char* pszKeyContainerName = NULL; // UUID + jobject privateKey = NULL; + + __try + { + if ((pszKeyContainerName = + env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { + __leave; + } + dwBlobLen = env->GetArrayLength(keyBlob); + if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) + == NULL) { + __leave; + } + + // Acquire a CSP context (create a new key container). + if (::CryptAcquireContext( //deprecated + &hCryptProv, + pszKeyContainerName, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET) == FALSE) + { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Import the private key + if (::CryptImportKey( //deprecated + hCryptProv, + pbKeyBlob, + dwBlobLen, + 0, + CRYPT_EXPORTABLE, + &hKey) == FALSE) + { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Get the method ID for the CPrivateKey constructor + jclass clazzCPrivateKey = + env->FindClass("sun/security/mscapi/CPrivateKey"); + if (clazzCPrivateKey == NULL) { + __leave; + } + + jmethodID mNewCPrivateKey = + env->GetStaticMethodID(clazzCPrivateKey, "of", + "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPrivateKey;"); + if (mNewCPrivateKey == NULL) { + __leave; + } + + // Create a new private key + privateKey = env->CallStaticObjectMethod(clazzCPrivateKey, mNewCPrivateKey, + alg, (jlong) hCryptProv, (jlong) hKey, keySize); + + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (pszKeyContainerName) + env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); + + if (pbKeyBlob) + env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob, + JNI_ABORT); + } + + return privateKey; +} + +/* + * Class: sun_security_mscapi_CSignature + * Method: importECPublicKey + * Signature: (Ljava/lang/String;[BI)Lsun/security/mscapi/CPublicKey; + */ +JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CSignature_importECPublicKey + (JNIEnv *env, jclass clazz, jstring alg, jbyteArray keyBlob, jint keySize) +{ + BCRYPT_ALG_HANDLE hSignAlg = NULL; + NCRYPT_KEY_HANDLE hTmpKey = NULL; + DWORD dwBlobLen; + BYTE * pbKeyBlob = NULL; + jobject publicKey = NULL; + + __try + { + dwBlobLen = env->GetArrayLength(keyBlob); + if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) + == NULL) { + __leave; + } + dump("NCryptImportKey", pbKeyBlob, dwBlobLen); + NCRYPT_PROV_HANDLE hProv; + SS_CHECK(NCryptOpenStorageProvider( + &hProv, L"Microsoft Software Key Storage Provider", 0 )); + SS_CHECK(NCryptImportKey( + hProv, + NULL, + BCRYPT_ECCPUBLIC_BLOB, + NULL, + &hTmpKey, + pbKeyBlob, + dwBlobLen, + 0)); + NCryptFreeObject( hProv ); + // Get the method ID for the CPublicKey constructor + jclass clazzCPublicKey = + env->FindClass("sun/security/mscapi/CPublicKey"); + if (clazzCPublicKey == NULL) { + __leave; + } + + jmethodID mNewCPublicKey = + env->GetStaticMethodID(clazzCPublicKey, "of", + "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPublicKey;"); + if (mNewCPublicKey == NULL) { + __leave; + } + + // Create a new public key + publicKey = env->CallStaticObjectMethod(clazzCPublicKey, mNewCPublicKey, + alg, (jlong) hTmpKey, (jlong) 0, keySize); + } + __finally + { + } + + return publicKey; +} + +/* + * Class: sun_security_mscapi_CSignature + * Method: importPublicKey + * Signature: (Ljava/lang/String;[BI)Lsun/security/mscapi/CPublicKey; + */ +JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CSignature_importPublicKey + (JNIEnv *env, jclass clazz, jstring alg, jbyteArray keyBlob, jint keySize) +{ + HCRYPTPROV hCryptProv = NULL; + HCRYPTKEY hKey = NULL; + DWORD dwBlobLen; + BYTE * pbKeyBlob = NULL; + jobject publicKey = NULL; + + __try + { + dwBlobLen = env->GetArrayLength(keyBlob); + if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) + == NULL) { + __leave; + } + + // Acquire a CSP context (create a new key container). + // Prefer a PROV_RSA_AES CSP, when available, due to its support + // for SHA-2-based signatures. + if (::CryptAcquireContext( //deprecated + &hCryptProv, + NULL, + NULL, + PROV_RSA_AES, + CRYPT_VERIFYCONTEXT) == FALSE) + { + // Failover to using the default CSP (PROV_RSA_FULL) + + if (::CryptAcquireContext( //deprecated + &hCryptProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT) == FALSE) + { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + } + + // Import the public key + if (::CryptImportKey( //deprecated + hCryptProv, + pbKeyBlob, + dwBlobLen, + 0, + CRYPT_EXPORTABLE, + &hKey) == FALSE) + { + ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); + __leave; + } + + // Get the method ID for the CPublicKey constructor + jclass clazzCPublicKey = + env->FindClass("sun/security/mscapi/CPublicKey"); + if (clazzCPublicKey == NULL) { + __leave; + } + + jmethodID mNewCPublicKey = + env->GetStaticMethodID(clazzCPublicKey, "of", + "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPublicKey;"); + if (mNewCPublicKey == NULL) { + __leave; + } + + // Create a new public key + publicKey = env->CallStaticObjectMethod(clazzCPublicKey, mNewCPublicKey, + alg, (jlong) hCryptProv, (jlong) hKey, keySize); + + } + __finally + { + //-------------------------------------------------------------------- + // Clean up. + + if (pbKeyBlob) + env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob, + JNI_ABORT); + } + + return publicKey; +} + +} /* extern "C" */ From 2918bfe1a4ca241bbddbcecf5a25f09319813823 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Fri, 14 Jun 2024 15:38:45 -0500 Subject: [PATCH 18/18] Include stdlib for free(): https://bugs.openjdk.org/browse/JDK-8315506 --- .../native/sun/nio/fs/LinuxNativeDispatcher.c | 531 +++++++++--------- 1 file changed, 266 insertions(+), 265 deletions(-) diff --git a/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c b/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c index bd836bfcd6b..b52bf378852 100644 --- a/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c +++ b/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c @@ -1,265 +1,266 @@ -/* - * Copyright (c) 2008, 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. - */ - -#include "jni.h" -#include "jni_util.h" -#include "jvm.h" -#include "jlong.h" - -#include -#include -#include -#include -#include - -#include "sun_nio_fs_LinuxNativeDispatcher.h" - -typedef size_t fgetxattr_func(int fd, const char* name, void* value, size_t size); -typedef int fsetxattr_func(int fd, const char* name, void* value, size_t size, int flags); -typedef int fremovexattr_func(int fd, const char* name); -typedef int flistxattr_func(int fd, char* list, size_t size); - -fgetxattr_func* my_fgetxattr_func = NULL; -fsetxattr_func* my_fsetxattr_func = NULL; -fremovexattr_func* my_fremovexattr_func = NULL; -flistxattr_func* my_flistxattr_func = NULL; - -static jfieldID entry_name; -static jfieldID entry_dir; -static jfieldID entry_fstype; -static jfieldID entry_options; - -static void throwUnixException(JNIEnv* env, int errnum) { - jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", - "(I)V", errnum); - if (x != NULL) { - (*env)->Throw(env, x); - } -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz) -{ - my_fgetxattr_func = (fgetxattr_func*)dlsym(RTLD_DEFAULT, "fgetxattr"); - my_fsetxattr_func = (fsetxattr_func*)dlsym(RTLD_DEFAULT, "fsetxattr"); - my_fremovexattr_func = (fremovexattr_func*)dlsym(RTLD_DEFAULT, "fremovexattr"); - my_flistxattr_func = (flistxattr_func*)dlsym(RTLD_DEFAULT, "flistxattr"); - - clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); - CHECK_NULL(clazz); - entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); - CHECK_NULL(entry_name); - entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); - CHECK_NULL(entry_dir); - entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); - CHECK_NULL(entry_fstype); - entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); - CHECK_NULL(entry_options); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) -{ - size_t res = -1; - const char* name = jlong_to_ptr(nameAddress); - void* value = jlong_to_ptr(valueAddress); - - if (my_fgetxattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_fgetxattr_func)(fd, name, value, valueLen); - } - if (res == (size_t)-1) - throwUnixException(env, errno); - return (jint)res; -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) -{ - int res = -1; - const char* name = jlong_to_ptr(nameAddress); - void* value = jlong_to_ptr(valueAddress); - - if (my_fsetxattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_fsetxattr_func)(fd, name, value, valueLen, 0); - } - if (res == -1) - throwUnixException(env, errno); -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, - jint fd, jlong nameAddress) -{ - int res = -1; - const char* name = jlong_to_ptr(nameAddress); - - if (my_fremovexattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_fremovexattr_func)(fd, name); - } - if (res == -1) - throwUnixException(env, errno); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, - jint fd, jlong listAddress, jint size) -{ - size_t res = -1; - char* list = jlong_to_ptr(listAddress); - - if (my_flistxattr_func == NULL) { - errno = ENOTSUP; - } else { - /* EINTR not documented */ - res = (*my_flistxattr_func)(fd, list, (size_t)size); - } - if (res == (size_t)-1) - throwUnixException(env, errno); - return (jint)res; -} - -JNIEXPORT jlong JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress, - jlong modeAddress) -{ - FILE* fp = NULL; - const char* path = (const char*)jlong_to_ptr(pathAddress); - const char* mode = (const char*)jlong_to_ptr(modeAddress); - - do { - fp = setmntent(path, mode); - } while (fp == NULL && errno == EINTR); - if (fp == NULL) { - throwUnixException(env, errno); - } - return ptr_to_jlong(fp); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_getmntent0(JNIEnv* env, jclass this, - jlong value, jobject entry, jlong buffer, jint bufLen) -{ - struct mntent ent; - char * buf = (char*)jlong_to_ptr(buffer); - struct mntent* m; - FILE* fp = jlong_to_ptr(value); - jsize len; - jbyteArray bytes; - char* name; - char* dir; - char* fstype; - char* options; - - m = getmntent_r(fp, &ent, buf, (int)bufLen); - if (m == NULL) - return -1; - name = m->mnt_fsname; - dir = m->mnt_dir; - fstype = m->mnt_type; - options = m->mnt_opts; - - len = strlen(name); - bytes = (*env)->NewByteArray(env, len); - if (bytes == NULL) - return -1; - (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); - (*env)->SetObjectField(env, entry, entry_name, bytes); - - len = strlen(dir); - bytes = (*env)->NewByteArray(env, len); - if (bytes == NULL) - return -1; - (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); - (*env)->SetObjectField(env, entry, entry_dir, bytes); - - len = strlen(fstype); - bytes = (*env)->NewByteArray(env, len); - if (bytes == NULL) - return -1; - (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); - (*env)->SetObjectField(env, entry, entry_fstype, bytes); - - len = strlen(options); - bytes = (*env)->NewByteArray(env, len); - if (bytes == NULL) - return -1; - (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); - (*env)->SetObjectField(env, entry, entry_options, bytes); - - return 0; -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong stream) -{ - FILE* fp = jlong_to_ptr(stream); - /* FIXME - man page doesn't explain how errors are returned */ - endmntent(fp); -} - -/** - * This function returns line length without NUL terminator or -1 on EOF. - * Since getline is missing on Solaris10 this function was moved from - * UnixNativeDispatcher to LinuxNativeDispatcher as part of backport form jdk11. - */ -JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_getlinelen(JNIEnv* env, jclass this, jlong stream) -{ - FILE* fp = jlong_to_ptr(stream); - size_t lineSize = 0; - char * lineBuffer = NULL; - int saved_errno; - - ssize_t res = getline(&lineBuffer, &lineSize, fp); - saved_errno = errno; - - /* Should free lineBuffer no matter result, according to man page */ - if (lineBuffer != NULL) - free(lineBuffer); - - if (feof(fp)) - return -1; - - /* On successfull return res >= 0, otherwise res is -1 */ - if (res == -1) - throwUnixException(env, saved_errno); - - if (res > INT_MAX) - throwUnixException(env, EOVERFLOW); - - return (jint)res; -} - +/* + * Copyright (c) 2008, 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. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include +#include +#include +#include +#include +#include + +#include "sun_nio_fs_LinuxNativeDispatcher.h" + +typedef size_t fgetxattr_func(int fd, const char* name, void* value, size_t size); +typedef int fsetxattr_func(int fd, const char* name, void* value, size_t size, int flags); +typedef int fremovexattr_func(int fd, const char* name); +typedef int flistxattr_func(int fd, char* list, size_t size); + +fgetxattr_func* my_fgetxattr_func = NULL; +fsetxattr_func* my_fsetxattr_func = NULL; +fremovexattr_func* my_fremovexattr_func = NULL; +flistxattr_func* my_flistxattr_func = NULL; + +static jfieldID entry_name; +static jfieldID entry_dir; +static jfieldID entry_fstype; +static jfieldID entry_options; + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz) +{ + my_fgetxattr_func = (fgetxattr_func*)dlsym(RTLD_DEFAULT, "fgetxattr"); + my_fsetxattr_func = (fsetxattr_func*)dlsym(RTLD_DEFAULT, "fsetxattr"); + my_fremovexattr_func = (fremovexattr_func*)dlsym(RTLD_DEFAULT, "fremovexattr"); + my_flistxattr_func = (flistxattr_func*)dlsym(RTLD_DEFAULT, "flistxattr"); + + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); + CHECK_NULL(clazz); + entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); + CHECK_NULL(entry_name); + entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); + CHECK_NULL(entry_dir); + entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); + CHECK_NULL(entry_fstype); + entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); + CHECK_NULL(entry_options); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) +{ + size_t res = -1; + const char* name = jlong_to_ptr(nameAddress); + void* value = jlong_to_ptr(valueAddress); + + if (my_fgetxattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_fgetxattr_func)(fd, name, value, valueLen); + } + if (res == (size_t)-1) + throwUnixException(env, errno); + return (jint)res; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress, jlong valueAddress, jint valueLen) +{ + int res = -1; + const char* name = jlong_to_ptr(nameAddress); + void* value = jlong_to_ptr(valueAddress); + + if (my_fsetxattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_fsetxattr_func)(fd, name, value, valueLen, 0); + } + if (res == -1) + throwUnixException(env, errno); +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz, + jint fd, jlong nameAddress) +{ + int res = -1; + const char* name = jlong_to_ptr(nameAddress); + + if (my_fremovexattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_fremovexattr_func)(fd, name); + } + if (res == -1) + throwUnixException(env, errno); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, + jint fd, jlong listAddress, jint size) +{ + size_t res = -1; + char* list = jlong_to_ptr(listAddress); + + if (my_flistxattr_func == NULL) { + errno = ENOTSUP; + } else { + /* EINTR not documented */ + res = (*my_flistxattr_func)(fd, list, (size_t)size); + } + if (res == (size_t)-1) + throwUnixException(env, errno); + return (jint)res; +} + +JNIEXPORT jlong JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress, + jlong modeAddress) +{ + FILE* fp = NULL; + const char* path = (const char*)jlong_to_ptr(pathAddress); + const char* mode = (const char*)jlong_to_ptr(modeAddress); + + do { + fp = setmntent(path, mode); + } while (fp == NULL && errno == EINTR); + if (fp == NULL) { + throwUnixException(env, errno); + } + return ptr_to_jlong(fp); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_getmntent0(JNIEnv* env, jclass this, + jlong value, jobject entry, jlong buffer, jint bufLen) +{ + struct mntent ent; + char * buf = (char*)jlong_to_ptr(buffer); + struct mntent* m; + FILE* fp = jlong_to_ptr(value); + jsize len; + jbyteArray bytes; + char* name; + char* dir; + char* fstype; + char* options; + + m = getmntent_r(fp, &ent, buf, (int)bufLen); + if (m == NULL) + return -1; + name = m->mnt_fsname; + dir = m->mnt_dir; + fstype = m->mnt_type; + options = m->mnt_opts; + + len = strlen(name); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); + (*env)->SetObjectField(env, entry, entry_name, bytes); + + len = strlen(dir); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); + (*env)->SetObjectField(env, entry, entry_dir, bytes); + + len = strlen(fstype); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); + (*env)->SetObjectField(env, entry, entry_fstype, bytes); + + len = strlen(options); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); + (*env)->SetObjectField(env, entry, entry_options, bytes); + + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + /* FIXME - man page doesn't explain how errors are returned */ + endmntent(fp); +} + +/** + * This function returns line length without NUL terminator or -1 on EOF. + * Since getline is missing on Solaris10 this function was moved from + * UnixNativeDispatcher to LinuxNativeDispatcher as part of backport form jdk11. + */ +JNIEXPORT jint JNICALL +Java_sun_nio_fs_LinuxNativeDispatcher_getlinelen(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + size_t lineSize = 0; + char * lineBuffer = NULL; + int saved_errno; + + ssize_t res = getline(&lineBuffer, &lineSize, fp); + saved_errno = errno; + + /* Should free lineBuffer no matter result, according to man page */ + if (lineBuffer != NULL) + free(lineBuffer); + + if (feof(fp)) + return -1; + + /* On successfull return res >= 0, otherwise res is -1 */ + if (res == -1) + throwUnixException(env, saved_errno); + + if (res > INT_MAX) + throwUnixException(env, EOVERFLOW); + + return (jint)res; +} +