diff --git a/src/share/classes/com/sun/jndi/ldap/LdapReferralContext.java b/src/share/classes/com/sun/jndi/ldap/LdapReferralContext.java index 0a09e0fda690a3e3388bb3faf39f098821053401..0b82340df537f1eac2db1721383cb5478563aa54 100644 --- a/src/share/classes/com/sun/jndi/ldap/LdapReferralContext.java +++ b/src/share/classes/com/sun/jndi/ldap/LdapReferralContext.java @@ -92,7 +92,12 @@ final class LdapReferralContext implements DirContext, LdapContext { try { referral = refEx.getNextReferral(); if (referral == null) { - throw (NamingException)(previousEx.fillInStackTrace()); + if (previousEx != null) { + throw (NamingException)(previousEx.fillInStackTrace()); + } else { + throw new NamingException( + "Illegal encoding: referral is empty"); + } } } catch (LdapReferralException e) { diff --git a/src/share/classes/java/net/URLPermission.java b/src/share/classes/java/net/URLPermission.java index 78373e1087f76a30dab7bcd22d5408c30d442001..e188c81d73b03c5763470f8bd9a427f99c7fcd94 100644 --- a/src/share/classes/java/net/URLPermission.java +++ b/src/share/classes/java/net/URLPermission.java @@ -170,7 +170,8 @@ public final class URLPermission extends Permission { parseURI(getName()); int colon = actions.indexOf(':'); if (actions.lastIndexOf(':') != colon) { - throw new IllegalArgumentException("invalid actions string"); + throw new IllegalArgumentException( + "Invalid actions string: \"" + actions + "\""); } String methods, headers; @@ -371,7 +372,8 @@ public final class URLPermission extends Permission { l.add(s); b = new StringBuilder(); } else if (c == ' ' || c == '\t') { - throw new IllegalArgumentException("white space not allowed"); + throw new IllegalArgumentException( + "White space not allowed in methods: \"" + methods + "\""); } else { if (c >= 'a' && c <= 'z') { c += 'A' - 'a'; @@ -398,7 +400,8 @@ public final class URLPermission extends Permission { } b.append(c); } else if (c == ' ' || c == '\t') { - throw new IllegalArgumentException("white space not allowed"); + throw new IllegalArgumentException( + "White space not allowed in headers: \"" + headers + "\""); } else if (c == '-') { capitalizeNext = true; b.append(c); @@ -423,14 +426,16 @@ public final class URLPermission extends Permission { int len = url.length(); int delim = url.indexOf(':'); if (delim == -1 || delim + 1 == len) { - throw new IllegalArgumentException("invalid URL string"); + throw new IllegalArgumentException( + "Invalid URL string: \"" + url + "\""); } scheme = url.substring(0, delim).toLowerCase(); this.ssp = url.substring(delim + 1); if (!ssp.startsWith("//")) { if (!ssp.equals("*")) { - throw new IllegalArgumentException("invalid URL string"); + throw new IllegalArgumentException( + "Invalid URL string: \"" + url + "\""); } this.authority = new Authority(scheme, "*"); return; diff --git a/src/share/classes/java/text/DateFormatSymbols.java b/src/share/classes/java/text/DateFormatSymbols.java index c1f951d5bf80bd3fee042e8b64de6f02dc880224..4fcde4eabb47eb500843b59a0946cf1737e3e095 100644 --- a/src/share/classes/java/text/DateFormatSymbols.java +++ b/src/share/classes/java/text/DateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ import java.util.Arrays; import java.util.Locale; import java.util.Objects; import java.util.ResourceBundle; -import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import sun.util.locale.provider.LocaleProviderAdapter; @@ -146,6 +145,12 @@ public class DateFormatSymbols implements Serializable, Cloneable { initializeData(locale); } + /** + * Constructs an uninitialized DateFormatSymbols. + */ + private DateFormatSymbols(boolean flag) { + } + /** * Era strings. For example: "AD" and "BC". An array of 2 strings, * indexed by Calendar.BC and Calendar.AD. @@ -677,54 +682,80 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ transient volatile int cachedHashCode = 0; - private void initializeData(Locale desiredLocale) { - locale = desiredLocale; - - // Copy values of a cached instance if any. + /** + * Initializes this DateFormatSymbols with the locale data. This method uses + * a cached DateFormatSymbols instance for the given locale if available. If + * there's no cached one, this method creates an uninitialized instance and + * populates its fields from the resource bundle for the locale, and caches + * the instance. Note: zoneStrings isn't initialized in this method. + */ + private void initializeData(Locale locale) { SoftReference ref = cachedInstances.get(locale); DateFormatSymbols dfs; - if (ref != null && (dfs = ref.get()) != null) { - copyMembers(dfs, this); - return; - } - - // Initialize the fields from the ResourceBundle for locale. - LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale); - // Avoid any potential recursions - if (!(adapter instanceof ResourceBundleBasedAdapter)) { - adapter = LocaleProviderAdapter.getResourceBundleBased(); - } - ResourceBundle resource = ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(locale); - - // JRE and CLDR use different keys - // JRE: Eras, short.Eras and narrow.Eras - // CLDR: long.Eras, Eras and narrow.Eras - if (resource.containsKey("Eras")) { - eras = resource.getStringArray("Eras"); - } else if (resource.containsKey("long.Eras")) { - eras = resource.getStringArray("long.Eras"); - } else if (resource.containsKey("short.Eras")) { - eras = resource.getStringArray("short.Eras"); - } - months = resource.getStringArray("MonthNames"); - shortMonths = resource.getStringArray("MonthAbbreviations"); - ampms = resource.getStringArray("AmPmMarkers"); - localPatternChars = resource.getString("DateTimePatternChars"); - - // Day of week names are stored in a 1-based array. - weekdays = toOneBasedArray(resource.getStringArray("DayNames")); - shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations")); - - // Put a clone in the cache - ref = new SoftReference<>((DateFormatSymbols)this.clone()); - SoftReference x = cachedInstances.putIfAbsent(locale, ref); - if (x != null) { - DateFormatSymbols y = x.get(); - if (y == null) { - // Replace the empty SoftReference with ref. - cachedInstances.put(locale, ref); + if (ref == null || (dfs = ref.get()) == null) { + if (ref != null) { + // Remove the empty SoftReference + cachedInstances.remove(locale, ref); + } + dfs = new DateFormatSymbols(false); + + // Initialize the fields from the ResourceBundle for locale. + LocaleProviderAdapter adapter + = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale); + // Avoid any potential recursions + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + ResourceBundle resource + = ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(locale); + + dfs.locale = locale; + // JRE and CLDR use different keys + // JRE: Eras, short.Eras and narrow.Eras + // CLDR: long.Eras, Eras and narrow.Eras + if (resource.containsKey("Eras")) { + dfs.eras = resource.getStringArray("Eras"); + } else if (resource.containsKey("long.Eras")) { + dfs.eras = resource.getStringArray("long.Eras"); + } else if (resource.containsKey("short.Eras")) { + dfs.eras = resource.getStringArray("short.Eras"); + } + dfs.months = resource.getStringArray("MonthNames"); + dfs.shortMonths = resource.getStringArray("MonthAbbreviations"); + dfs.ampms = resource.getStringArray("AmPmMarkers"); + dfs.localPatternChars = resource.getString("DateTimePatternChars"); + + // Day of week names are stored in a 1-based array. + dfs.weekdays = toOneBasedArray(resource.getStringArray("DayNames")); + dfs.shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations")); + + // Put dfs in the cache + ref = new SoftReference<>(dfs); + SoftReference x = cachedInstances.putIfAbsent(locale, ref); + if (x != null) { + DateFormatSymbols y = x.get(); + if (y == null) { + // Replace the empty SoftReference with ref. + cachedInstances.replace(locale, x, ref); + } else { + ref = x; + dfs = y; + } + } + // If the bundle's locale isn't the target locale, put another cache + // entry for the bundle's locale. + Locale bundleLocale = resource.getLocale(); + if (!bundleLocale.equals(locale)) { + SoftReference z + = cachedInstances.putIfAbsent(bundleLocale, ref); + if (z != null && z.get() == null) { + cachedInstances.replace(bundleLocale, z, ref); + } } } + + // Copy the field values from dfs to this instance. + copyMembers(dfs, this); } private static String[] toOneBasedArray(String[] src) { @@ -806,12 +837,14 @@ public class DateFormatSymbols implements Serializable, Cloneable { /** * Clones all the data members from the source DateFormatSymbols to - * the target DateFormatSymbols. This is only for subclasses. + * the target DateFormatSymbols. + * * @param src the source DateFormatSymbols. * @param dst the target DateFormatSymbols. */ private void copyMembers(DateFormatSymbols src, DateFormatSymbols dst) { + dst.locale = src.locale; dst.eras = Arrays.copyOf(src.eras, src.eras.length); dst.months = Arrays.copyOf(src.months, src.months.length); dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length); diff --git a/src/share/classes/sun/invoke/anon/AnonymousClassLoader.java b/src/share/classes/sun/invoke/anon/AnonymousClassLoader.java deleted file mode 100644 index 32624b40f97760719159031009f43824d5d5790d..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/invoke/anon/AnonymousClassLoader.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2008, 2012, 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 sun.invoke.anon; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import sun.misc.IOUtils; - -/** - * Anonymous class loader. Will load any valid classfile, producing - * a {@link Class} metaobject, without installing that class in the - * system dictionary. Therefore, {@link Class#forName(String)} will never - * produce a reference to an anonymous class. - *

- * The access permissions of the anonymous class are borrowed from - * a host class. The new class behaves as if it were an - * inner class of the host class. It can access the host's private - * members, if the creator of the class loader has permission to - * do so (or to create accessible reflective objects). - *

- * When the anonymous class is loaded, elements of its constant pool - * can be patched to new values. This provides a hook to pre-resolve - * named classes in the constant pool to other classes, including - * anonymous ones. Also, string constants can be pre-resolved to - * any reference. (The verifier treats non-string, non-class reference - * constants as plain objects.) - *

- * Why include the patching function? It makes some use cases much easier. - * Second, the constant pool needed some internal patching anyway, - * to anonymize the loaded class itself. Finally, if you are going - * to use this seriously, you'll want to build anonymous classes - * on top of pre-existing anonymous classes, and that requires patching. - * - *

%%% TO-DO: - *

    - *
  • needs better documentation
  • - *
  • needs more security work (for safe delegation)
  • - *
  • needs a clearer story about error processing
  • - *
  • patch member references also (use ';' as delimiter char)
  • - *
  • patch method references to (conforming) method handles
  • - *
- * - * @author jrose - * @author Remi Forax - * @see - * http://blogs.sun.com/jrose/entry/anonymous_classes_in_the_vm - */ - -public class AnonymousClassLoader { - final Class hostClass; - - // Privileged constructor. - private AnonymousClassLoader(Class hostClass) { - this.hostClass = hostClass; - } - - public static AnonymousClassLoader make(sun.misc.Unsafe unsafe, Class hostClass) { - if (unsafe == null) throw new NullPointerException(); - return new AnonymousClassLoader(hostClass); - } - - public Class loadClass(byte[] classFile) { - if (defineAnonymousClass == null) { - // no JVM support; try to fake an approximation - try { - return fakeLoadClass(new ConstantPoolParser(classFile).createPatch()); - } catch (InvalidConstantPoolFormatException ee) { - throw new IllegalArgumentException(ee); - } - } - return loadClass(classFile, null); - } - - public Class loadClass(ConstantPoolPatch classPatch) { - if (defineAnonymousClass == null) { - // no JVM support; try to fake an approximation - return fakeLoadClass(classPatch); - } - Object[] patches = classPatch.patchArray; - // Convert class names (this late in the game) - // to use slash '/' instead of dot '.'. - // Java likes dots, but the JVM likes slashes. - for (int i = 0; i < patches.length; i++) { - Object value = patches[i]; - if (value != null) { - byte tag = classPatch.getTag(i); - switch (tag) { - case ConstantPoolVisitor.CONSTANT_Class: - if (value instanceof String) { - if (patches == classPatch.patchArray) - patches = patches.clone(); - patches[i] = ((String)value).replace('.', '/'); - } - break; - case ConstantPoolVisitor.CONSTANT_Fieldref: - case ConstantPoolVisitor.CONSTANT_Methodref: - case ConstantPoolVisitor.CONSTANT_InterfaceMethodref: - case ConstantPoolVisitor.CONSTANT_NameAndType: - // When/if the JVM supports these patches, - // we'll probably need to reformat them also. - // Meanwhile, let the class loader create the error. - break; - } - } - } - return loadClass(classPatch.outer.classFile, classPatch.patchArray); - } - - private Class loadClass(byte[] classFile, Object[] patchArray) { - try { - return (Class) - defineAnonymousClass.invoke(unsafe, - hostClass, classFile, patchArray); - } catch (Exception ex) { - throwReflectedException(ex); - throw new RuntimeException("error loading into "+hostClass, ex); - } - } - - private static void throwReflectedException(Exception ex) { - if (ex instanceof InvocationTargetException) { - Throwable tex = ((InvocationTargetException)ex).getTargetException(); - if (tex instanceof Error) - throw (Error) tex; - ex = (Exception) tex; - } - if (ex instanceof RuntimeException) { - throw (RuntimeException) ex; - } - } - - private Class fakeLoadClass(ConstantPoolPatch classPatch) { - // Implementation: - // 1. Make up a new name nobody has used yet. - // 2. Inspect the tail-header of the class to find the this_class index. - // 3. Patch the CONSTANT_Class for this_class to the new name. - // 4. Add other CP entries required by (e.g.) string patches. - // 5. Flatten Class constants down to their names, making sure that - // the host class loader can pick them up again accurately. - // 6. Generate the edited class file bytes. - // - // Potential limitations: - // * The class won't be truly anonymous, and may interfere with others. - // * Flattened class constants might not work, because of loader issues. - // * Pseudo-string constants will not flatten down to real strings. - // * Method handles will (of course) fail to flatten to linkage strings. - if (true) throw new UnsupportedOperationException("NYI"); - Object[] cpArray; - try { - cpArray = classPatch.getOriginalCP(); - } catch (InvalidConstantPoolFormatException ex) { - throw new RuntimeException(ex); - } - int thisClassIndex = classPatch.getParser().getThisClassIndex(); - String thisClassName = (String) cpArray[thisClassIndex]; - synchronized (AnonymousClassLoader.class) { - thisClassName = thisClassName+"\\|"+(++fakeNameCounter); - } - classPatch.putUTF8(thisClassIndex, thisClassName); - byte[] classFile = null; - return unsafe.defineClass(null, classFile, 0, classFile.length, - hostClass.getClassLoader(), - hostClass.getProtectionDomain()); - } - private static int fakeNameCounter = 99999; - - // ignore two warnings on this line: - private static sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); - // preceding line requires that this class be on the boot class path - - static private final Method defineAnonymousClass; - static { - Method dac = null; - Class unsafeClass = unsafe.getClass(); - try { - dac = unsafeClass.getMethod("defineAnonymousClass", - Class.class, - byte[].class, - Object[].class); - } catch (Exception ee) { - dac = null; - } - defineAnonymousClass = dac; - } - - private static void noJVMSupport() { - throw new UnsupportedOperationException("no JVM support for anonymous classes"); - } - - - private static native Class loadClassInternal(Class hostClass, - byte[] classFile, - Object[] patchArray); - - public static byte[] readClassFile(Class templateClass) throws IOException { - String templateName = templateClass.getName(); - int lastDot = templateName.lastIndexOf('.'); - java.net.URL url = templateClass.getResource(templateName.substring(lastDot+1)+".class"); - java.net.URLConnection connection = url.openConnection(); - int contentLength = connection.getContentLength(); - if (contentLength < 0) - throw new IOException("invalid content length "+contentLength); - - return IOUtils.readFully(connection.getInputStream(), contentLength, true); - } -} diff --git a/src/share/classes/sun/invoke/anon/ConstantPoolParser.java b/src/share/classes/sun/invoke/anon/ConstantPoolParser.java deleted file mode 100644 index 441ba9573365b0b1961f84ae297f8fc09c948b87..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/invoke/anon/ConstantPoolParser.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; - -import static sun.invoke.anon.ConstantPoolVisitor.*; - -/** A constant pool parser. - */ -public class ConstantPoolParser { - final byte[] classFile; - final byte[] tags; - final char[] firstHeader; // maghi, maglo, minor, major, cplen - - // these are filled in on first parse: - int endOffset; - char[] secondHeader; // flags, this_class, super_class, intlen - - // used to decode UTF8 array - private char[] charArray = new char[80]; - - /** Creates a constant pool parser. - * @param classFile an array of bytes containing a class. - * @throws InvalidConstantPoolFormatException if the header of the class has errors. - */ - public ConstantPoolParser(byte[] classFile) throws InvalidConstantPoolFormatException { - this.classFile = classFile; - this.firstHeader = parseHeader(classFile); - this.tags = new byte[firstHeader[4]]; - } - - /** Create a constant pool parser by loading the bytecodes of the - * class taken as argument. - * - * @param templateClass the class to parse. - * - * @throws IOException raised if an I/O occurs when loading - * the bytecode of the template class. - * @throws InvalidConstantPoolFormatException if the header of the class has errors. - * - * @see #ConstantPoolParser(byte[]) - * @see AnonymousClassLoader#readClassFile(Class) - */ - public ConstantPoolParser(Class templateClass) throws IOException, InvalidConstantPoolFormatException { - this(AnonymousClassLoader.readClassFile(templateClass)); - } - - /** Creates an empty patch to patch the class file - * used by the current parser. - * @return a new class patch. - */ - public ConstantPoolPatch createPatch() { - return new ConstantPoolPatch(this); - } - - /** Report the tag of the indicated CP entry. - * @param index - * @return one of {@link ConstantPoolVisitor#CONSTANT_Utf8}, etc. - */ - public byte getTag(int index) { - getEndOffset(); // trigger an exception if we haven't parsed yet - return tags[index]; - } - - /** Report the length of the constant pool. */ - public int getLength() { - return firstHeader[4]; - } - - /** Report the offset, within the class file, of the start of the constant pool. */ - public int getStartOffset() { - return firstHeader.length * 2; - } - - /** Report the offset, within the class file, of the end of the constant pool. */ - public int getEndOffset() { - if (endOffset == 0) - throw new IllegalStateException("class file has not yet been parsed"); - return endOffset; - } - - /** Report the CP index of this class's own name. */ - public int getThisClassIndex() { - getEndOffset(); // provoke exception if not yet parsed - return secondHeader[1]; - } - - /** Report the total size of the class file. */ - public int getTailLength() { - return classFile.length - getEndOffset(); - } - - /** Write the head (header plus constant pool) - * of the class file to the indicated stream. - */ - public void writeHead(OutputStream out) throws IOException { - out.write(classFile, 0, getEndOffset()); - } - - /** Write the head (header plus constant pool) - * of the class file to the indicated stream, - * incorporating the non-null entries of the given array - * as patches. - */ - void writePatchedHead(OutputStream out, Object[] patchArray) { - // this will be useful to partially emulate the class loader on old JVMs - throw new UnsupportedOperationException("Not yet implemented"); - } - - /** Write the tail (everything after the constant pool) - * of the class file to the indicated stream. - */ - public void writeTail(OutputStream out) throws IOException { - out.write(classFile, getEndOffset(), getTailLength()); - } - - private static char[] parseHeader(byte[] classFile) throws InvalidConstantPoolFormatException { - char[] result = new char[5]; - ByteBuffer buffer = ByteBuffer.wrap(classFile); - for (int i = 0; i < result.length; i++) - result[i] = (char) getUnsignedShort(buffer); - int magic = result[0] << 16 | result[1] << 0; - if (magic != 0xCAFEBABE) - throw new InvalidConstantPoolFormatException("invalid magic number "+magic); - // skip major, minor version - int len = result[4]; - if (len < 1) - throw new InvalidConstantPoolFormatException("constant pool length < 1"); - return result; - } - - /** Parse the constant pool of the class - * calling a method visit* each time a constant pool entry is parsed. - * - * The order of the calls to visit* is not guaranteed to be the same - * than the order of the constant pool entry in the bytecode array. - * - * @param visitor - * @throws InvalidConstantPoolFormatException - */ - public void parse(ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException { - ByteBuffer buffer = ByteBuffer.wrap(classFile); - buffer.position(getStartOffset()); //skip header - - Object[] values = new Object[getLength()]; - try { - parseConstantPool(buffer, values, visitor); - } catch(BufferUnderflowException e) { - throw new InvalidConstantPoolFormatException(e); - } - if (endOffset == 0) { - endOffset = buffer.position(); - secondHeader = new char[4]; - for (int i = 0; i < secondHeader.length; i++) { - secondHeader[i] = (char) getUnsignedShort(buffer); - } - } - resolveConstantPool(values, visitor); - } - - private char[] getCharArray(int utfLength) { - if (utfLength <= charArray.length) - return charArray; - return charArray = new char[utfLength]; - } - - private void parseConstantPool(ByteBuffer buffer, Object[] values, ConstantPoolVisitor visitor) throws InvalidConstantPoolFormatException { - for (int i = 1; i < tags.length; ) { - byte tag = (byte) getUnsignedByte(buffer); - assert(tags[i] == 0 || tags[i] == tag); - tags[i] = tag; - switch (tag) { - case CONSTANT_Utf8: - int utfLen = getUnsignedShort(buffer); - String value = getUTF8(buffer, utfLen, getCharArray(utfLen)); - visitor.visitUTF8(i, CONSTANT_Utf8, value); - tags[i] = tag; - values[i++] = value; - break; - case CONSTANT_Integer: - visitor.visitConstantValue(i, tag, buffer.getInt()); - i++; - break; - case CONSTANT_Float: - visitor.visitConstantValue(i, tag, buffer.getFloat()); - i++; - break; - case CONSTANT_Long: - visitor.visitConstantValue(i, tag, buffer.getLong()); - i+=2; - break; - case CONSTANT_Double: - visitor.visitConstantValue(i, tag, buffer.getDouble()); - i+=2; - break; - - case CONSTANT_Class: // fall through: - case CONSTANT_String: - tags[i] = tag; - values[i++] = new int[] { getUnsignedShort(buffer) }; - break; - - case CONSTANT_Fieldref: // fall through: - case CONSTANT_Methodref: // fall through: - case CONSTANT_InterfaceMethodref: // fall through: - case CONSTANT_NameAndType: - tags[i] = tag; - values[i++] = new int[] { getUnsignedShort(buffer), getUnsignedShort(buffer) }; - break; - default: - throw new AssertionError("invalid constant "+tag); - } - } - } - - private void resolveConstantPool(Object[] values, ConstantPoolVisitor visitor) { - // clean out the int[] values, which are temporary - for (int beg = 1, end = values.length-1, beg2, end2; - beg <= end; - beg = beg2, end = end2) { - beg2 = end; end2 = beg-1; - //System.out.println("CP resolve pass: "+beg+".."+end); - for (int i = beg; i <= end; i++) { - Object value = values[i]; - if (!(value instanceof int[])) - continue; - int[] array = (int[]) value; - byte tag = tags[i]; - switch (tag) { - case CONSTANT_String: - String stringBody = (String) values[array[0]]; - visitor.visitConstantString(i, tag, stringBody, array[0]); - values[i] = null; - break; - case CONSTANT_Class: { - String className = (String) values[array[0]]; - // use the external form favored by Class.forName: - className = className.replace('/', '.'); - visitor.visitConstantString(i, tag, className, array[0]); - values[i] = className; - break; - } - case CONSTANT_NameAndType: { - String memberName = (String) values[array[0]]; - String signature = (String) values[array[1]]; - visitor.visitDescriptor(i, tag, memberName, signature, - array[0], array[1]); - values[i] = new String[] {memberName, signature}; - break; - } - case CONSTANT_Fieldref: // fall through: - case CONSTANT_Methodref: // fall through: - case CONSTANT_InterfaceMethodref: { - Object className = values[array[0]]; - Object nameAndType = values[array[1]]; - if (!(className instanceof String) || - !(nameAndType instanceof String[])) { - // one more pass is needed - if (beg2 > i) beg2 = i; - if (end2 < i) end2 = i; - continue; - } - String[] nameAndTypeArray = (String[]) nameAndType; - visitor.visitMemberRef(i, tag, - (String)className, - nameAndTypeArray[0], - nameAndTypeArray[1], - array[0], array[1]); - values[i] = null; - } - break; - default: - continue; - } - } - } - } - - private static int getUnsignedByte(ByteBuffer buffer) { - return buffer.get() & 0xFF; - } - - private static int getUnsignedShort(ByteBuffer buffer) { - int b1 = getUnsignedByte(buffer); - int b2 = getUnsignedByte(buffer); - return (b1 << 8) + (b2 << 0); - } - - private static String getUTF8(ByteBuffer buffer, int utfLen, char[] charArray) throws InvalidConstantPoolFormatException { - int utfLimit = buffer.position() + utfLen; - int index = 0; - while (buffer.position() < utfLimit) { - int c = buffer.get() & 0xff; - if (c > 127) { - buffer.position(buffer.position() - 1); - return getUTF8Extended(buffer, utfLimit, charArray, index); - } - charArray[index++] = (char)c; - } - return new String(charArray, 0, index); - } - - private static String getUTF8Extended(ByteBuffer buffer, int utfLimit, char[] charArray, int index) throws InvalidConstantPoolFormatException { - int c, c2, c3; - while (buffer.position() < utfLimit) { - c = buffer.get() & 0xff; - switch (c >> 4) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - /* 0xxxxxxx*/ - charArray[index++] = (char)c; - break; - case 12: case 13: - /* 110x xxxx 10xx xxxx*/ - c2 = buffer.get(); - if ((c2 & 0xC0) != 0x80) - throw new InvalidConstantPoolFormatException( - "malformed input around byte " + buffer.position()); - charArray[index++] = (char)(((c & 0x1F) << 6) | - (c2 & 0x3F)); - break; - case 14: - /* 1110 xxxx 10xx xxxx 10xx xxxx */ - c2 = buffer.get(); - c3 = buffer.get(); - if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) - throw new InvalidConstantPoolFormatException( - "malformed input around byte " + (buffer.position())); - charArray[index++] = (char)(((c & 0x0F) << 12) | - ((c2 & 0x3F) << 6) | - ((c3 & 0x3F) << 0)); - break; - default: - /* 10xx xxxx, 1111 xxxx */ - throw new InvalidConstantPoolFormatException( - "malformed input around byte " + buffer.position()); - } - } - // The number of chars produced may be less than utflen - return new String(charArray, 0, index); - } -} diff --git a/src/share/classes/sun/invoke/anon/ConstantPoolPatch.java b/src/share/classes/sun/invoke/anon/ConstantPoolPatch.java deleted file mode 100644 index d83c2a6d61a3bbd99d9008a581b4bde95632a17b..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/invoke/anon/ConstantPoolPatch.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Map; - -import static sun.invoke.anon.ConstantPoolVisitor.*; - -/** A class and its patched constant pool. - * - * This class allow to modify (patch) a constant pool - * by changing the value of its entry. - * Entry are referenced using index that can be get - * by parsing the constant pool using - * {@link ConstantPoolParser#parse(ConstantPoolVisitor)}. - * - * @see ConstantPoolVisitor - * @see ConstantPoolParser#createPatch() - */ -public class ConstantPoolPatch { - final ConstantPoolParser outer; - final Object[] patchArray; - - ConstantPoolPatch(ConstantPoolParser outer) { - this.outer = outer; - this.patchArray = new Object[outer.getLength()]; - } - - /** Create a {@link ConstantPoolParser} and - * a {@link ConstantPoolPatch} in one step. - * Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}. - * - * @param classFile an array of bytes containing a class. - * @see #ConstantPoolParser(Class) - */ - public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException { - this(new ConstantPoolParser(classFile)); - } - - /** Create a {@link ConstantPoolParser} and - * a {@link ConstantPoolPatch} in one step. - * Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}. - * - * @param templateClass the class to parse. - * @see #ConstantPoolParser(Class) - */ - public ConstantPoolPatch(Class templateClass) throws IOException, InvalidConstantPoolFormatException { - this(new ConstantPoolParser(templateClass)); - } - - - /** Creates a patch from an existing patch. - * All changes are copied from that patch. - * @param patch a patch - * - * @see ConstantPoolParser#createPatch() - */ - public ConstantPoolPatch(ConstantPoolPatch patch) { - outer = patch.outer; - patchArray = patch.patchArray.clone(); - } - - /** Which parser built this patch? */ - public ConstantPoolParser getParser() { - return outer; - } - - /** Report the tag at the given index in the constant pool. */ - public byte getTag(int index) { - return outer.getTag(index); - } - - /** Report the current patch at the given index of the constant pool. - * Null means no patch will be made. - * To observe the unpatched entry at the given index, use - * {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)} - */ - public Object getPatch(int index) { - Object value = patchArray[index]; - if (value == null) return null; - switch (getTag(index)) { - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - if (value instanceof String) - value = stripSemis(2, (String) value); - break; - case CONSTANT_NameAndType: - if (value instanceof String) - value = stripSemis(1, (String) value); - break; - } - return value; - } - - /** Clear all patches. */ - public void clear() { - Arrays.fill(patchArray, null); - } - - /** Clear one patch. */ - public void clear(int index) { - patchArray[index] = null; - } - - /** Produce the patches as an array. */ - public Object[] getPatches() { - return patchArray.clone(); - } - - /** Produce the original constant pool as an array. */ - public Object[] getOriginalCP() throws InvalidConstantPoolFormatException { - return getOriginalCP(0, patchArray.length, -1); - } - - /** Walk the constant pool, applying patches using the given map. - * - * @param utf8Map Utf8 strings to modify, if encountered - * @param classMap Classes (or their names) to modify, if encountered - * @param valueMap Constant values to modify, if encountered - * @param deleteUsedEntries if true, delete map entries that are used - */ - public void putPatches(final Map utf8Map, - final Map classMap, - final Map valueMap, - boolean deleteUsedEntries) throws InvalidConstantPoolFormatException { - final HashSet usedUtf8Keys; - final HashSet usedClassKeys; - final HashSet usedValueKeys; - if (deleteUsedEntries) { - usedUtf8Keys = (utf8Map == null) ? null : new HashSet(); - usedClassKeys = (classMap == null) ? null : new HashSet(); - usedValueKeys = (valueMap == null) ? null : new HashSet(); - } else { - usedUtf8Keys = null; - usedClassKeys = null; - usedValueKeys = null; - } - - outer.parse(new ConstantPoolVisitor() { - - @Override - public void visitUTF8(int index, byte tag, String utf8) { - putUTF8(index, utf8Map.get(utf8)); - if (usedUtf8Keys != null) usedUtf8Keys.add(utf8); - } - - @Override - public void visitConstantValue(int index, byte tag, Object value) { - putConstantValue(index, tag, valueMap.get(value)); - if (usedValueKeys != null) usedValueKeys.add(value); - } - - @Override - public void visitConstantString(int index, byte tag, String name, int nameIndex) { - if (tag == CONSTANT_Class) { - putConstantValue(index, tag, classMap.get(name)); - if (usedClassKeys != null) usedClassKeys.add(name); - } else { - assert(tag == CONSTANT_String); - visitConstantValue(index, tag, name); - } - } - }); - if (usedUtf8Keys != null) utf8Map.keySet().removeAll(usedUtf8Keys); - if (usedClassKeys != null) classMap.keySet().removeAll(usedClassKeys); - if (usedValueKeys != null) valueMap.keySet().removeAll(usedValueKeys); - } - - Object[] getOriginalCP(final int startIndex, - final int endIndex, - final int tagMask) throws InvalidConstantPoolFormatException { - final Object[] cpArray = new Object[endIndex - startIndex]; - outer.parse(new ConstantPoolVisitor() { - - void show(int index, byte tag, Object value) { - if (index < startIndex || index >= endIndex) return; - if (((1 << tag) & tagMask) == 0) return; - cpArray[index - startIndex] = value; - } - - @Override - public void visitUTF8(int index, byte tag, String utf8) { - show(index, tag, utf8); - } - - @Override - public void visitConstantValue(int index, byte tag, Object value) { - assert(tag != CONSTANT_String); - show(index, tag, value); - } - - @Override - public void visitConstantString(int index, byte tag, - String value, int j) { - show(index, tag, value); - } - - @Override - public void visitMemberRef(int index, byte tag, - String className, String memberName, - String signature, - int j, int k) { - show(index, tag, new String[]{ className, memberName, signature }); - } - - @Override - public void visitDescriptor(int index, byte tag, - String memberName, String signature, - int j, int k) { - show(index, tag, new String[]{ memberName, signature }); - } - }); - return cpArray; - } - - /** Write the head (header plus constant pool) - * of the patched class file to the indicated stream. - */ - void writeHead(OutputStream out) throws IOException { - outer.writePatchedHead(out, patchArray); - } - - /** Write the tail (everything after the constant pool) - * of the patched class file to the indicated stream. - */ - void writeTail(OutputStream out) throws IOException { - outer.writeTail(out); - } - - private void checkConstantTag(byte tag, Object value) { - if (value == null) - throw new IllegalArgumentException( - "invalid null constant value"); - if (classForTag(tag) != value.getClass()) - throw new IllegalArgumentException( - "invalid constant value" - + (tag == CONSTANT_None ? "" - : " for tag "+tagName(tag)) - + " of class "+value.getClass()); - } - - private void checkTag(int index, byte putTag) { - byte tag = outer.tags[index]; - if (tag != putTag) - throw new IllegalArgumentException( - "invalid put operation" - + " for " + tagName(putTag) - + " at index " + index + " found " + tagName(tag)); - } - - private void checkTagMask(int index, int tagBitMask) { - byte tag = outer.tags[index]; - int tagBit = ((tag & 0x1F) == tag) ? (1 << tag) : 0; - if ((tagBit & tagBitMask) == 0) - throw new IllegalArgumentException( - "invalid put operation" - + " at index " + index + " found " + tagName(tag)); - } - - private static void checkMemberName(String memberName) { - if (memberName.indexOf(';') >= 0) - throw new IllegalArgumentException("memberName " + memberName + " contains a ';'"); - } - - /** Set the entry of the constant pool indexed by index to - * a new string. - * - * @param index an index to a constant pool entry containing a - * {@link ConstantPoolVisitor#CONSTANT_Utf8} value. - * @param utf8 a string - * - * @see ConstantPoolVisitor#visitUTF8(int, byte, String) - */ - public void putUTF8(int index, String utf8) { - if (utf8 == null) { clear(index); return; } - checkTag(index, CONSTANT_Utf8); - patchArray[index] = utf8; - } - - /** Set the entry of the constant pool indexed by index to - * a new value, depending on its dynamic type. - * - * @param index an index to a constant pool entry containing a - * one of the following structures: - * {@link ConstantPoolVisitor#CONSTANT_Integer}, - * {@link ConstantPoolVisitor#CONSTANT_Float}, - * {@link ConstantPoolVisitor#CONSTANT_Long}, - * {@link ConstantPoolVisitor#CONSTANT_Double}, - * {@link ConstantPoolVisitor#CONSTANT_String}, or - * {@link ConstantPoolVisitor#CONSTANT_Class} - * @param value a boxed int, float, long or double; or a string or class object - * @throws IllegalArgumentException if the type of the constant does not - * match the constant pool entry type, - * as reported by {@link #getTag(int)} - * - * @see #putConstantValue(int, byte, Object) - * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object) - * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int) - */ - public void putConstantValue(int index, Object value) { - if (value == null) { clear(index); return; } - byte tag = tagForConstant(value.getClass()); - checkConstantTag(tag, value); - checkTag(index, tag); - patchArray[index] = value; - } - - /** Set the entry of the constant pool indexed by index to - * a new value. - * - * @param index an index to a constant pool entry matching the given tag - * @param tag one of the following values: - * {@link ConstantPoolVisitor#CONSTANT_Integer}, - * {@link ConstantPoolVisitor#CONSTANT_Float}, - * {@link ConstantPoolVisitor#CONSTANT_Long}, - * {@link ConstantPoolVisitor#CONSTANT_Double}, - * {@link ConstantPoolVisitor#CONSTANT_String}, or - * {@link ConstantPoolVisitor#CONSTANT_Class} - * @param value a boxed number, string, or class object - * @throws IllegalArgumentException if the type of the constant does not - * match the constant pool entry type, or if a class name contains - * '/' or ';' - * - * @see #putConstantValue(int, Object) - * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object) - * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int) - */ - public void putConstantValue(int index, byte tag, Object value) { - if (value == null) { clear(index); return; } - checkTag(index, tag); - if (tag == CONSTANT_Class && value instanceof String) { - checkClassName((String) value); - } else if (tag == CONSTANT_String) { - // the JVM accepts any object as a patch for a string - } else { - // make sure the incoming value is the right type - checkConstantTag(tag, value); - } - checkTag(index, tag); - patchArray[index] = value; - } - - /** Set the entry of the constant pool indexed by index to - * a new {@link ConstantPoolVisitor#CONSTANT_NameAndType} value. - * - * @param index an index to a constant pool entry containing a - * {@link ConstantPoolVisitor#CONSTANT_NameAndType} value. - * @param memberName a memberName - * @param signature a signature - * @throws IllegalArgumentException if memberName contains the character ';' - * - * @see ConstantPoolVisitor#visitDescriptor(int, byte, String, String, int, int) - */ - public void putDescriptor(int index, String memberName, String signature) { - checkTag(index, CONSTANT_NameAndType); - checkMemberName(memberName); - patchArray[index] = addSemis(memberName, signature); - } - - /** Set the entry of the constant pool indexed by index to - * a new {@link ConstantPoolVisitor#CONSTANT_Fieldref}, - * {@link ConstantPoolVisitor#CONSTANT_Methodref}, or - * {@link ConstantPoolVisitor#CONSTANT_InterfaceMethodref} value. - * - * @param index an index to a constant pool entry containing a member reference - * @param className a class name - * @param memberName a field or method name - * @param signature a field or method signature - * @throws IllegalArgumentException if memberName contains the character ';' - * or signature is not a correct signature - * - * @see ConstantPoolVisitor#visitMemberRef(int, byte, String, String, String, int, int) - */ - public void putMemberRef(int index, byte tag, - String className, String memberName, String signature) { - checkTagMask(tag, CONSTANT_MemberRef_MASK); - checkTag(index, tag); - checkClassName(className); - checkMemberName(memberName); - if (signature.startsWith("(") == (tag == CONSTANT_Fieldref)) - throw new IllegalArgumentException("bad signature: "+signature); - patchArray[index] = addSemis(className, memberName, signature); - } - - static private final int CONSTANT_MemberRef_MASK = - CONSTANT_Fieldref - | CONSTANT_Methodref - | CONSTANT_InterfaceMethodref; - - private static final Map, Byte> CONSTANT_VALUE_CLASS_TAG - = new IdentityHashMap, Byte>(); - private static final Class[] CONSTANT_VALUE_CLASS = new Class[16]; - static { - Object[][] values = { - {Integer.class, CONSTANT_Integer}, - {Long.class, CONSTANT_Long}, - {Float.class, CONSTANT_Float}, - {Double.class, CONSTANT_Double}, - {String.class, CONSTANT_String}, - {Class.class, CONSTANT_Class} - }; - for (Object[] value : values) { - Class cls = (Class)value[0]; - Byte tag = (Byte) value[1]; - CONSTANT_VALUE_CLASS_TAG.put(cls, tag); - CONSTANT_VALUE_CLASS[(byte)tag] = cls; - } - } - - static Class classForTag(byte tag) { - if ((tag & 0xFF) >= CONSTANT_VALUE_CLASS.length) - return null; - return CONSTANT_VALUE_CLASS[tag]; - } - - static byte tagForConstant(Class cls) { - Byte tag = CONSTANT_VALUE_CLASS_TAG.get(cls); - return (tag == null) ? CONSTANT_None : (byte)tag; - } - - private static void checkClassName(String className) { - if (className.indexOf('/') >= 0 || className.indexOf(';') >= 0) - throw new IllegalArgumentException("invalid class name " + className); - } - - static String addSemis(String name, String... names) { - StringBuilder buf = new StringBuilder(name.length() * 5); - buf.append(name); - for (String name2 : names) { - buf.append(';').append(name2); - } - String res = buf.toString(); - assert(stripSemis(names.length, res)[0].equals(name)); - assert(stripSemis(names.length, res)[1].equals(names[0])); - assert(names.length == 1 || - stripSemis(names.length, res)[2].equals(names[1])); - return res; - } - - static String[] stripSemis(int count, String string) { - String[] res = new String[count+1]; - int pos = 0; - for (int i = 0; i < count; i++) { - int pos2 = string.indexOf(';', pos); - if (pos2 < 0) pos2 = string.length(); // yuck - res[i] = string.substring(pos, pos2); - pos = pos2; - } - res[count] = string.substring(pos); - return res; - } - - public String toString() { - StringBuilder buf = new StringBuilder(this.getClass().getName()); - buf.append("{"); - Object[] origCP = null; - for (int i = 0; i < patchArray.length; i++) { - if (patchArray[i] == null) continue; - if (origCP != null) { - buf.append(", "); - } else { - try { - origCP = getOriginalCP(); - } catch (InvalidConstantPoolFormatException ee) { - origCP = new Object[0]; - } - } - Object orig = (i < origCP.length) ? origCP[i] : "?"; - buf.append(orig).append("=").append(patchArray[i]); - } - buf.append("}"); - return buf.toString(); - } -} diff --git a/src/share/classes/sun/invoke/anon/ConstantPoolVisitor.java b/src/share/classes/sun/invoke/anon/ConstantPoolVisitor.java deleted file mode 100644 index dfec8b41151e22664f6d41c2932bae26c2301202..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/invoke/anon/ConstantPoolVisitor.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.invoke.anon; - -/** - * A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)} - * when a constant pool entry is parsed. - *

- * A visit* method is called when a constant pool entry is parsed. - * The first argument is always the constant pool index. - * The second argument is always the constant pool tag, - * even for methods like {@link #visitUTF8(int, byte, String)} which only apply to one tag. - * String arguments refer to Utf8 or NameAndType entries declared elsewhere, - * and are always accompanied by the indexes of those entries. - *

- * The order of the calls to the visit* methods is not necessarily related - * to the order of the entries in the constant pool. - * If one entry has a reference to another entry, the latter (lower-level) - * entry will be visited first. - *

- * The following table shows the relation between constant pool entry - * types and the corresponding visit* methods: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Tag(s)Method
{@link #CONSTANT_Utf8}{@link #visitUTF8(int, byte, String)}
{@link #CONSTANT_Integer}, {@link #CONSTANT_Float}, - * {@link #CONSTANT_Long}, {@link #CONSTANT_Double}{@link #visitConstantValue(int, byte, Object)}
{@link #CONSTANT_String}, {@link #CONSTANT_Class}{@link #visitConstantString(int, byte, String, int)}
{@link #CONSTANT_NameAndType}{@link #visitDescriptor(int, byte, String, String, int, int)}
{@link #CONSTANT_Fieldref}, - * {@link #CONSTANT_Methodref}, - * {@link #CONSTANT_InterfaceMethodref}{@link #visitMemberRef(int, byte, String, String, String, int, int)}
- * - * @see ConstantPoolPatch - * @author Remi Forax - * @author jrose - */ -public class ConstantPoolVisitor { - /** Called each time an UTF8 constant pool entry is found. - * @param index the constant pool index - * @param tag always {@link #CONSTANT_Utf8} - * @param utf8 string encoded in modified UTF-8 format passed as a {@code String} - * - * @see ConstantPoolPatch#putUTF8(int, String) - */ - public void visitUTF8(int index, byte tag, String utf8) { - // do nothing - } - - /** Called for each constant pool entry that encodes an integer, - * a float, a long, or a double. - * Constant strings and classes are not managed by this method but - * by {@link #visitConstantString(int, byte, String, int)}. - * - * @param index the constant pool index - * @param tag one of {@link #CONSTANT_Integer}, - * {@link #CONSTANT_Float}, - * {@link #CONSTANT_Long}, - * or {@link #CONSTANT_Double} - * @param value encoded value - * - * @see ConstantPoolPatch#putConstantValue(int, Object) - */ - public void visitConstantValue(int index, byte tag, Object value) { - // do nothing - } - - /** Called for each constant pool entry that encodes a string or a class. - * @param index the constant pool index - * @param tag one of {@link #CONSTANT_String}, - * {@link #CONSTANT_Class}, - * @param name string body or class name (using dot separator) - * @param nameIndex the index of the Utf8 string for the name - * - * @see ConstantPoolPatch#putConstantValue(int, byte, Object) - */ - public void visitConstantString(int index, byte tag, - String name, int nameIndex) { - // do nothing - } - - /** Called for each constant pool entry that encodes a name and type. - * @param index the constant pool index - * @param tag always {@link #CONSTANT_NameAndType} - * @param memberName a field or method name - * @param signature the member signature - * @param memberNameIndex index of the Utf8 string for the member name - * @param signatureIndex index of the Utf8 string for the signature - * - * @see ConstantPoolPatch#putDescriptor(int, String, String) - */ - public void visitDescriptor(int index, byte tag, - String memberName, String signature, - int memberNameIndex, int signatureIndex) { - // do nothing - } - - /** Called for each constant pool entry that encodes a field or method. - * @param index the constant pool index - * @param tag one of {@link #CONSTANT_Fieldref}, - * or {@link #CONSTANT_Methodref}, - * or {@link #CONSTANT_InterfaceMethodref} - * @param className the class name (using dot separator) - * @param memberName name of the field or method - * @param signature the field or method signature - * @param classNameIndex index of the Utf8 string for the class name - * @param descriptorIndex index of the NameAndType descriptor constant - * - * @see ConstantPoolPatch#putMemberRef(int, byte, String, String, String) - */ - public void visitMemberRef(int index, byte tag, - String className, String memberName, String signature, - int classNameIndex, int descriptorIndex) { - // do nothing - } - - public static final byte - CONSTANT_None = 0, - CONSTANT_Utf8 = 1, - //CONSTANT_Unicode = 2, /* unused */ - CONSTANT_Integer = 3, - CONSTANT_Float = 4, - CONSTANT_Long = 5, - CONSTANT_Double = 6, - CONSTANT_Class = 7, - CONSTANT_String = 8, - CONSTANT_Fieldref = 9, - CONSTANT_Methodref = 10, - CONSTANT_InterfaceMethodref = 11, - CONSTANT_NameAndType = 12; - - private static String[] TAG_NAMES = { - "Empty", - "Utf8", - null, //"Unicode", - "Integer", - "Float", - "Long", - "Double", - "Class", - "String", - "Fieldref", - "Methodref", - "InterfaceMethodref", - "NameAndType" - }; - - public static String tagName(byte tag) { - String name = null; - if ((tag & 0xFF) < TAG_NAMES.length) - name = TAG_NAMES[tag]; - if (name == null) - name = "Unknown#"+(tag&0xFF); - return name; - } -} diff --git a/test/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java b/test/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9b1dd1cb3736d871deefc32d8bfc272e263a6c79 --- /dev/null +++ b/test/com/sun/crypto/provider/Mac/EmptyByteBufferTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import javax.crypto.Mac; +import javax.crypto.SecretKey; + +/** + * @test + * @bug 8048603 + * @summary Checks if MAC algorithms work fine with empty buffer + * @author Alexander Fomin + * @build Utils + * @run main EmptyByteBufferTest + */ +public class EmptyByteBufferTest implements MacTest { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + Utils.runTests(new EmptyByteBufferTest()); + } + + @Override + public void doTest(String alg) throws NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException { + SecretKey key = Utils.getSecretKeySpec(); + + // instantiate Mac object and init it with a SecretKey + Mac mac = Mac.getInstance(alg, "SunJCE"); + mac.init(key); + + // prepare buffer + byte[] data = new byte[0]; + ByteBuffer buf = ByteBuffer.wrap(data); + + mac.update(buf); + mac.doFinal(); + } + +} diff --git a/test/com/sun/crypto/provider/Mac/LargeByteBufferTest.java b/test/com/sun/crypto/provider/Mac/LargeByteBufferTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f294b67743b9a4f8133fb54aa64adca05e98ba49 --- /dev/null +++ b/test/com/sun/crypto/provider/Mac/LargeByteBufferTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import javax.crypto.Mac; +import javax.crypto.SecretKey; + +/** + * @test + * @bug 8048603 + * @summary Checks if PBE algorithms work fine with large buffer + * @author Alexander Fomin + * @build Utils + * @run main LargeByteBufferTest + */ +public class LargeByteBufferTest implements MacTest { + + private static final int BUFFER_SIZE = 65535; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + Utils.runTests(new LargeByteBufferTest()); + } + + @Override + public void doTest(String alg) throws NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException { + SecretKey key = Utils.getSecretKeySpec(); + + // instantiate Mac object and init it with a SecretKey + Mac mac = Mac.getInstance(alg, "SunJCE"); + mac.init(key); + + // prepare buffer + byte[] data = new byte[BUFFER_SIZE]; + for (int i = 0; i < BUFFER_SIZE; i++) { + data[i] = (byte) (i % 256); + } + + ByteBuffer buf = ByteBuffer.wrap(data); + int limitBefore = buf.limit(); + + mac.update(buf); + mac.doFinal(); + + int limitAfter = buf.limit(); + int positonAfter = buf.position(); + + if (limitAfter != limitBefore) { + System.out.println("limit after = " + limitAfter); + System.out.println("limit before = " + limitBefore); + throw new RuntimeException("Test failed: " + + "limit of buffer has been chenged."); + } + + if (positonAfter != limitAfter) { + System.out.println("position after = " + positonAfter); + System.out.println("limit after = " + limitAfter); + throw new RuntimeException("Test failed: " + + "position of buffer isn't equal to its limit"); + } + } + +} diff --git a/test/com/sun/crypto/provider/Mac/MacSameTest.java b/test/com/sun/crypto/provider/Mac/MacSameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8d97f1a6a88fac919fe870e591f81811f814856d --- /dev/null +++ b/test/com/sun/crypto/provider/Mac/MacSameTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +/** + * @test + * @bug 8048603 + * @summary Check if doFinal and update operation result in same Mac + * @author Yu-Ching Valerie Peng, Bill Situ, Alexander Fomin + * @build Utils + * @run main MacSameTest + */ +public class MacSameTest implements MacTest { + + private static final int MESSAGE_SIZE = 25; + private static final int OFFSET = 5; + private static final int KEY_SIZE = 70; + + /** + * Initialize a message, instantiate a Mac object, + * initialize the object with a SecretKey, + * feed the message into the Mac object + * all at once and get the output MAC as result1. + * Reset the Mac object, chop the message into three pieces, + * feed into the Mac object sequentially, and get the output MAC as result2. + * Finally, compare result1 and result2 and see if they are the same. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + Utils.runTests(new MacSameTest()); + } + + @Override + public void doTest(String algo) throws NoSuchAlgorithmException, + NoSuchProviderException, InvalidKeyException { + Mac mac; + try { + mac = Mac.getInstance(algo, "SunJCE"); + } catch (NoSuchAlgorithmException nsae) { + // depending on Solaris configuration, + // it can support HMAC or not with Mac + System.out.println("Expected NoSuchAlgorithmException thrown: " + + nsae); + return; + } + + byte[] plain = new byte[MESSAGE_SIZE]; + for (int i = 0; i < MESSAGE_SIZE; i++) { + plain[i] = (byte) (i % 256); + } + + byte[] tail = new byte[plain.length - OFFSET]; + System.arraycopy(plain, OFFSET, tail, 0, tail.length); + + SecureRandom srdm = new SecureRandom(); + byte[] keyVal = new byte[KEY_SIZE]; + srdm.nextBytes(keyVal); + SecretKeySpec keySpec = new SecretKeySpec(keyVal, "HMAC"); + + mac.init(keySpec); + byte[] result1 = mac.doFinal(plain); + + mac.reset(); + mac.update(plain[0]); + mac.update(plain, 1, OFFSET - 1); + byte[] result2 = mac.doFinal(tail); + + if (!java.util.Arrays.equals(result1, result2)) { + throw new RuntimeException("result1 and result2 are not the same"); + } + } + +} diff --git a/test/com/sun/crypto/provider/Mac/NullByteBufferTest.java b/test/com/sun/crypto/provider/Mac/NullByteBufferTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d71d4f96317667ed62fb2a76509420985fcec594 --- /dev/null +++ b/test/com/sun/crypto/provider/Mac/NullByteBufferTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import javax.crypto.Mac; +import javax.crypto.SecretKey; + +/** + * @test + * @bug 8048603 + * @summary Checks if PBE algorithms work fine with null buffer + * @author Alexander Fomin + * @build Utils + * @run main NullByteBufferTest + */ +public class NullByteBufferTest implements MacTest { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + Utils.runTests(new NullByteBufferTest()); + } + + @Override + public void doTest(String alg) throws NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException { + SecretKey key = Utils.getSecretKeySpec(); + + // instantiate Mac object and init it with a SecretKey + Mac mac = Mac.getInstance(alg, "SunJCE"); + mac.init(key); + + try { + ByteBuffer buf = null; + mac.update(buf); + mac.doFinal(); + throw new RuntimeException( + "Expected IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) { + System.out.println("Expected IllegalArgumentException thrown: " + + e); + } + } + +} diff --git a/test/com/sun/crypto/provider/Mac/Utils.java b/test/com/sun/crypto/provider/Mac/Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..389d40b0d14e4665a9212c3cdfedc2c272595320 --- /dev/null +++ b/test/com/sun/crypto/provider/Mac/Utils.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.security.SecureRandom; +import javax.crypto.spec.SecretKeySpec; + +/** + * Helper class. + */ +class Utils { + + static final int KEY_SIZE = 70; + + static final String[] MAC_ALGOS = {"HmacMD5", "HmacSHA1", "HmacSHA224", + "HmacSHA256", "HmacSHA384", "HmacSHA512"}; + + /** + * Get SecretKeySpec. + */ + static SecretKeySpec getSecretKeySpec() { + SecureRandom srdm = new SecureRandom(); + byte[] keyVal = new byte[KEY_SIZE]; + srdm.nextBytes(keyVal); + return new SecretKeySpec(keyVal, "HMAC"); + } + + static void runTests(MacTest... tests) { + boolean success = true; + for (MacTest test : tests) { + success &= runTest(test); + } + + if (success) { + System.out.println("Test passed"); + } else { + throw new RuntimeException("Test failed"); + } + } + + private static boolean runTest(MacTest test) { + boolean success = true; + for (String alg : MAC_ALGOS) { + try { + System.out.println("Test " + alg); + test.doTest(alg); + } catch (Exception e) { + System.out.println("Unexpected exception:"); + e.printStackTrace(); + success = false; + } + } + + return success; + } +} + +interface MacTest { + void doTest(String alg) throws Exception; +} \ No newline at end of file diff --git a/test/java/security/MessageDigest/TestSameLength.java b/test/java/security/MessageDigest/TestSameLength.java new file mode 100644 index 0000000000000000000000000000000000000000..eb59815c9bdea9d148c002af0494202d37ff9727 --- /dev/null +++ b/test/java/security/MessageDigest/TestSameLength.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import static java.lang.System.out; + +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.util.Random; + +/** + * @test + * @bug 8050371 + * @summary Check md.getDigestLength() equal digest output length with various + * algorithm/dataLen/(update,digest methods). + * @author Kevin Liu + */ + +public class TestSameLength { + + public static void main(String[] args) throws Exception { + TestSameLength test = new TestSameLength(); + test.run(); + } + + private void run() throws Exception { + String[] algorithmArr = { + "SHA", "Sha", "SHA-1", "sha-1", "SHA1", "sha1", "MD5", "md5", + "SHA-224", "SHA-256", "SHA-384", "SHA-512" + }; + int[] nUpdatesArr = { + 0, 1, 2, 3 + }; + int[] dataLenArr = { + 1, 50, 2500, 125000, 6250000 + }; + + for (String algorithm: algorithmArr) { + for (UpdateMethod update: UpdateMethod.values()) { + for (int dataLen: dataLenArr) { + if (!runTest(algorithm, dataLen, update)) { + throw new RuntimeException( + "Test failed at algorithm/dataLen/numUpdate:" + + algorithm + "/" + dataLen + "/" + + update.toString()); + } + } + } + } + + out.println("All " + algorithmArr.length * nUpdatesArr.length + * dataLenArr.length + " tests Passed"); + } + + private boolean runTest(String algo, long dataLen, + UpdateMethod whichUpdate) throws Exception { + try { + // Do initialization + byte[] data = new byte[(int) dataLen]; + new Random().nextBytes(data); + MessageDigest md = MessageDigest.getInstance(algo); + int outputLen = md.getDigestLength(); + + // Perform the update using all available/possible update methods + whichUpdate.updateDigest(data, md, dataLen); + // Get the output + byte[] output = md.digest(); + + // Compare input and output + return outputLen == output.length; + } catch (Exception ex) { + System.err.println("Testing: " + algo + "/" + dataLen + "/" + + whichUpdate.toString() + + " failed with unexpected exception"); + ex.printStackTrace(); + throw ex; + } + } + + private static enum UpdateMethod { + UPDATE_BYTE { + @Override + public void updateDigest(byte[] data, + MessageDigest md, long dataLen) { + + for (int i = 0; i < dataLen; i++) { + md.update(data[i]); + } + } + }, + + UPDATE_BUFFER { + @Override + public void updateDigest(byte[] data, + MessageDigest md, long dataLen) { + + md.update(data); + } + }, + + UPDATE_BUFFER_LEN { + @Override + public void updateDigest(byte[] data, + MessageDigest md, long dataLen) { + + for (int i = 0; i < dataLen; i++) { + md.update(data, i, 1); + } + } + }, + + UPDATE_BYTE_BUFFER { + @Override + public void updateDigest(byte[] data, + MessageDigest md, long dataLen) { + + md.update(ByteBuffer.wrap(data)); + } + }; + + public abstract void updateDigest(byte[] data, + MessageDigest md, long dataLen); + } +} diff --git a/test/java/security/MessageDigest/TestSameValue.java b/test/java/security/MessageDigest/TestSameValue.java new file mode 100644 index 0000000000000000000000000000000000000000..aef4ceae402c9c9a500caea571411d0cd76eaf7e --- /dev/null +++ b/test/java/security/MessageDigest/TestSameValue.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import static java.lang.System.out; + +import java.nio.ByteBuffer; +import java.security.DigestException; +import java.security.MessageDigest; +import java.util.Random; + +/** + * @test + * @bug 8050371 + * @summary Check md.digest(data) value whether same with digest output value + * with various update/digest methods. + * @author Kevin Liu + */ + +public class TestSameValue { + + public static void main(String[] args) throws Exception { + TestSameValue test1 = new TestSameValue(); + test1.run(); + } + + private void run() throws Exception { + + byte[] data = new byte[6706]; + MessageDigest md = null; + // Initialize input data + new Random().nextBytes(data); + + String[] providers = { + null, "SUN" + }; + String[] algorithmArr = { + "SHA", "Sha", "MD5", "md5", "SHA-224", "SHA-256", "SHA-384", + "SHA-512" + }; + + for (String algorithm: algorithmArr) { + for (String provider: providers) { + if (provider != null) { + md = MessageDigest.getInstance(algorithm, provider); + } else { + md = MessageDigest.getInstance(algorithm); + } + for (UpdateDigestMethod updateMethod: UpdateDigestMethod + .values()) { + byte[] output = updateMethod.updateDigest(data, md); + // Get the output and the "correct" one + byte[] standard = md.digest(data); + // Compare input and output + if (!MessageDigest.isEqual(output, standard)) { + throw new RuntimeException( + "Test failed at algorithm/provider/numUpdate:" + + algorithm + "/" + provider + "/" + + updateMethod); + } + } + } + } + + out.println("All " + algorithmArr.length + * UpdateDigestMethod.values().length * providers.length + + " tests Passed"); + } + + private static enum UpdateDigestMethod { + + /* + * update the data one by one using method update(byte input) then + * do digest (giving the output buffer, offset, and the number of + * bytes to put in the output buffer) + */ + UPDATE_DIGEST_BUFFER { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) + throws DigestException { + for (byte element: data) { + md.update(element); + } + byte[] output = new byte[md.getDigestLength()]; + int len = md.digest(output, 0, output.length); + if (len != output.length) { + throw new RuntimeException( + "ERROR" + ": digest length differs!"); + } + return output; + } + }, + + /* + * update the data one by one using method update(byte input) + * then do digest + */ + UPDATE_DIGEST { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) { + for (byte element: data) { + md.update(element); + } + return md.digest(); + } + }, + + /* + * update all the data at once as a block, then do digest ( giving the + * output buffer, offset, and the number of bytes to put in the output + * buffer) + */ + UPDATE_BLOCK_DIGEST_BUFFER { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) + throws DigestException { + md.update(data); + byte[] output = new byte[md.getDigestLength()]; + int len = md.digest(output, 0, output.length); + if (len != output.length) { + throw new RuntimeException( + "ERROR" + ": digest length differs!"); + } + return output; + } + }, + + // update all the data at once as a block, then do digest + UPDATE_BLOCK_DIGEST { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) { + md.update(data); + return md.digest(); + } + }, + + /* + * update the leading bytes (length is "data.length-LASTNBYTES") + * at once as a block, then do digest (do a final update using + * the left LASTNBYTES bytes which is passed as a parameter for + * the digest method, then complete the digest) + */ + UPDATE_LEADING_BLOCK_DIGEST_REMAIN { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) { + byte[] mainPart = new byte[data.length - LASTNBYTES]; + for (int i = 0; i < mainPart.length; i++) { + mainPart[i] = data[i]; + } + for (int j = 0; j < LASTNBYTES; j++) { + REMAIN[j] = data[data.length - LASTNBYTES + j]; + } + md.update(mainPart); + return md.digest(REMAIN); + } + }, + + /* + * update the data 2 bytes each time, after finishing updating, + * do digest (giving the output buffer, offset, and the number + * of bytes to put in the output buffer) + */ + UPDATE_BYTES_DIGEST_BUFFER { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) + throws DigestException { + + for (int i = 0; i < data.length / 2; i++) { + md.update(data, i * 2, 2); + } + byte[] output = new byte[md.getDigestLength()]; + int len = md.digest(output, 0, output.length); + if (len != output.length) { + throw new RuntimeException( + "ERROR" + ": digest length differs!"); + } + return output; + } + }, + + /* + * update the data 2 bytes each time, after finishing updating, + * do digest + */ + UPDATE_BYTES_DIGEST { + @Override + public byte[] updateDigest(byte[] data, MessageDigest md) { + for (int i=0;i constructedMap = new HashMap<>(); + + public static void main(String[] args) throws Exception { + + // initializations + int len = ids.length; + Object[] values = { + new ObjectIdentifier("1.2.3.4"), + new GregorianCalendar(1970, 1, 25, 8, 56, 7).getTime(), + "challenging" + }; + for (int j = 0; j < len; j++) { + constructedMap.put(ids[j], values[j]); + } + + X500Name subject = new X500Name("cn=Test"); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); + String sigAlg = "DSA"; + + keyGen.initialize(512); + + KeyPair pair = keyGen.generateKeyPair(); + X509Key publicKey = (X509Key) pair.getPublic(); + PrivateKey privateKey = pair.getPrivate(); + + Signature signature = Signature.getInstance(sigAlg); + signature.initSign(privateKey); + + // Create the PKCS10 request + PKCS10Attribute[] attrs = new PKCS10Attribute[len]; + for (int j = 0; j < len; j++) { + attrs[j] = new PKCS10Attribute(ids[j], values[j]); + } + PKCS10 req = new PKCS10(publicKey, new PKCS10Attributes(attrs)); + System.out.println("List of attributes in constructed PKCS10 " + + "request: "); + checkAttributes(req.getAttributes().getElements()); + + // Encode the PKCS10 request and generate another PKCS10 request from + // the encoded byte array + req.encodeAndSign(subject, signature); + PKCS10 resp = new PKCS10(req.getEncoded()); + System.out.println("List of attributes in DER encoded PKCS10 Request:"); + checkAttributes(resp.getAttributes().getElements()); + + if (failedCount > 0) { + throw new RuntimeException("Attributes Compared : Failed"); + } + System.out.println("Attributes Compared : Pass"); + } + + static void checkAttributes(Enumeration attrs) { + int numOfAttrs = 0; + while (attrs.hasMoreElements()) { + numOfAttrs ++; + PKCS10Attribute attr = (PKCS10Attribute) attrs.nextElement(); + + if (constructedMap.containsKey(attr.getAttributeId())) { + if (constructedMap.get(attr.getAttributeId()). + equals(attr.getAttributeValue())) { + System.out.print("AttributeId: " + attr.getAttributeId()); + System.out.println(" AttributeValue: " + + attr.getAttributeValue()); + } else { + failedCount++; + System.out.print("< AttributeId: " + attr.getAttributeId()); + System.out.println(" AttributeValue: " + constructedMap. + get(attr.getAttributeId())); + System.out.print("< AttributeId: " + attr.getAttributeId()); + System.out.println(" AttributeValue: " + + attr.getAttributeValue()); + } + } else { + failedCount++; + System.out.println("No " + attr.getAttributeId() + + " in DER encoded PKCS10 Request"); + } + } + if(numOfAttrs != constructedMap.size()){ + failedCount++; + System.out.println("Incorrect number of attributes."); + + } + System.out.println(); + } + +} diff --git a/test/sun/security/pkcs/pkcs10/PKCS10AttributeReader.java b/test/sun/security/pkcs/pkcs10/PKCS10AttributeReader.java new file mode 100644 index 0000000000000000000000000000000000000000..d5bde6d63aae03ffe9196f6b81592416a0db7890 --- /dev/null +++ b/test/sun/security/pkcs/pkcs10/PKCS10AttributeReader.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 8048357 + * @summary Read in a file containing a DER encoded PKCS10 certificate request, + * flanked with "begin" and "end" lines. + * @compile -XDignore.symbol.file PKCS10AttributeReader.java + * @run main PKCS10AttributeReader + */ +import java.util.Base64; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Date; +import sun.security.pkcs.PKCS9Attribute; +import sun.security.pkcs10.PKCS10Attribute; +import sun.security.pkcs10.PKCS10Attributes; +import sun.security.util.DerInputStream; +import sun.security.util.ObjectIdentifier; + +/* + Tests only reads DER encoding files, contents of corresponding asn.1 files + are copied below for reference. + + # An attribute set for testing with PKCS10. + + {A0 # implicit tag + {SEQ # Content Type + {OID 1.2.840.113549.1.9.3} + {SET + {OID "1234"} + } + } + {SEQ # Challenge Password + {OID 1.2.840.113549.1.9.7} + {SET + {T61String "GuessWhoAmI"} + } + } + {SEQ # Signing Time + {OID 1.2.840.113549.1.9.5} + {SET + {UTCTime "970422145010Z"} + } + } + } + */ +public class PKCS10AttributeReader { + // DER encoded files are binary files, to avoid attaching binary files, + // DER files were encoded in base64 + static final String ATTRIBS = "oE8wEwYJKoZIhvcNAQkDMQYGBDEyMzQwGgYJKoZIhv" + + "cNAQkHMQ0UC0d1ZXNzV2hv\nQW1JMBwGCSqGSIb3DQEJBTEPFw05NzA0MjIxND" + + "UwMTBa"; + + public static void main(String[] args) throws Exception { + + // Decode base64 encoded DER file + byte[] pkcs10Bytes = Base64.getMimeDecoder().decode(ATTRIBS.getBytes()); + + HashMap RequestStander = new HashMap() { + { + put(PKCS9Attribute.CHALLENGE_PASSWORD_OID, "GuessWhoAmI"); + put(PKCS9Attribute.SIGNING_TIME_OID, new Date(861720610000L)); + put(PKCS9Attribute.CONTENT_TYPE_OID, + new ObjectIdentifier("1.9.50.51.52")); + } + }; + + int invalidNum = 0; + PKCS10Attributes resp = new PKCS10Attributes( + new DerInputStream(pkcs10Bytes)); + Enumeration eReq = resp.getElements(); + int numOfAttrs = 0; + while (eReq.hasMoreElements()) { + numOfAttrs++; + PKCS10Attribute attr = (PKCS10Attribute) eReq.nextElement(); + if (RequestStander.containsKey(attr.getAttributeId())) { + if (RequestStander.get(attr.getAttributeId()) + .equals(attr.getAttributeValue())) { + System.out.println(attr.getAttributeId() + " " + + attr.getAttributeValue()); + } else { + invalidNum++; + System.out.println("< " + attr.getAttributeId() + " " + + attr.getAttributeValue()); + System.out.println("< " + attr.getAttributeId() + " " + + RequestStander.get(attr.getAttributeId())); + } + } else { + invalidNum++; + System.out.println("No" + attr.getAttributeId() + + "in Certificate Request list"); + } + } + if (numOfAttrs != RequestStander.size()) { + invalidNum++; + System.out.println("Incorrect number of attributes."); + } + System.out.println(); + if (invalidNum > 0) { + throw new RuntimeException( + "Attributes Compared with Stander :" + " Failed"); + } + System.out.println("Attributes Compared with Stander: Pass"); + } + +} diff --git a/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java b/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..24cc111befa08831b0fe411dc58773a4d702e4e7 --- /dev/null +++ b/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 8048357 + * @summary Read signed data in one or more PKCS7 objects from individual files, + * verify SignerInfos and certificate chain. + * @run main PKCS7VerifyTest PKCS7TEST.DSA.base64 + * @run main PKCS7VerifyTest PKCS7TEST.DSA.base64 PKCS7TEST.SF + */ +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import sun.security.pkcs.PKCS7; +import sun.security.pkcs.SignerInfo; + +public class PKCS7VerifyTest { + + static final String TESTSRC = System.getProperty("test.src", "."); + static final String FS = File.separator; + static final String FILEPATH = TESTSRC + FS + "jarsigner" + FS + "META-INF" + + FS; + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + throw new RuntimeException("usage: java JarVerify "); + } + + // The command " java PKCS7VerifyTest file1 [file2] " + // treats file1 as containing the DER encoding of a PKCS7 signed data + // object. If file2 is absent, the program verifies that some signature + // (SignerInfo) file1 correctly signs the data contained in the + // ContentInfo component of the PKCS7 object encoded by file1. If file2 + // is present, the program verifies file1 contains a correct signature + // for the contents of file2. + + PKCS7 pkcs7; + byte[] data; + + // to avoid attaching binary DSA file, the DSA file was encoded + // in Base64, decode encoded Base64 DSA file below + byte[] base64Bytes = Files.readAllBytes(Paths.get(FILEPATH + args[0])); + pkcs7 = new PKCS7(new ByteArrayInputStream( + Base64.getMimeDecoder().decode(base64Bytes))); + if (args.length < 2) { + data = null; + } else { + data = Files.readAllBytes(Paths.get(FILEPATH + args[1])); + + } + + SignerInfo[] signerInfos = pkcs7.verify(data); + + if (signerInfos == null) { + throw new RuntimeException("no signers verify"); + } + System.out.println("Verifying SignerInfos:"); + for (SignerInfo signerInfo : signerInfos) { + System.out.println(signerInfo.toString()); + } + + X509Certificate certs[] = pkcs7.getCertificates(); + + HashMap certTable = new HashMap(certs.length); + for (X509Certificate cert : certs) { + certTable.put(cert.getSubjectDN().toString(), cert); + } + + // try to verify all the certs + for (Map.Entry entry : certTable.entrySet()) { + + X509Certificate cert = entry.getValue(); + X509Certificate issuerCert = certTable + .get(cert.getIssuerDN().toString()); + + System.out.println("Subject: " + cert.getSubjectDN()); + if (issuerCert == null) { + System.out.println("Issuer certificate not found"); + } else { + System.out.println("Issuer: " + cert.getIssuerDN()); + cert.verify(issuerCert.getPublicKey()); + System.out.println("Cert verifies."); + } + System.out.println(); + } + } + +} diff --git a/test/sun/security/pkcs/pkcs7/SignerOrder.java b/test/sun/security/pkcs/pkcs7/SignerOrder.java new file mode 100644 index 0000000000000000000000000000000000000000..1848b4374dd09802fa0ab9a78b51cbb0e187188e --- /dev/null +++ b/test/sun/security/pkcs/pkcs7/SignerOrder.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 8048357 + * @summary test PKCS7 data signing, encoding and verification + * @run main SignerOrder + */ +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.X509Certificate; +import java.util.Date; +import sun.misc.HexDumpEncoder; +import sun.security.pkcs.ContentInfo; +import sun.security.pkcs.PKCS7; +import sun.security.pkcs.SignerInfo; +import sun.security.util.DerOutputStream; +import sun.security.x509.AlgorithmId; +import sun.security.x509.CertificateAlgorithmId; +import sun.security.x509.CertificateSerialNumber; +import sun.security.x509.CertificateValidity; +import sun.security.x509.CertificateVersion; +import sun.security.x509.CertificateX509Key; +import sun.security.x509.X500Name; +import sun.security.x509.X509CertImpl; +import sun.security.x509.X509CertInfo; +import sun.security.x509.X509Key; + +public class SignerOrder { + + static final HexDumpEncoder hexDump = new HexDumpEncoder(); + + //signer infos + static final byte[] data1 = "12345".getBytes(); + static final byte[] data2 = "abcde".getBytes(); + + public static void main(String[] argv) throws Exception { + + SignerInfo[] signerInfos = new SignerInfo[9]; + SimpleSigner signer1 = new SimpleSigner(null, null, null, null); + signerInfos[8] = signer1.genSignerInfo(data1); + signerInfos[7] = signer1.genSignerInfo(new byte[]{}); + signerInfos[6] = signer1.genSignerInfo(data2); + + SimpleSigner signer2 = new SimpleSigner(null, null, null, null); + signerInfos[5] = signer2.genSignerInfo(data1); + signerInfos[4] = signer2.genSignerInfo(new byte[]{}); + signerInfos[3] = signer2.genSignerInfo(data2); + + SimpleSigner signer3 = new SimpleSigner(null, null, null, null); + signerInfos[2] = signer3.genSignerInfo(data1); + signerInfos[1] = signer3.genSignerInfo(new byte[]{}); + signerInfos[0] = signer3.genSignerInfo(data2); + + ContentInfo contentInfo = new ContentInfo(data1); + + AlgorithmId[] algIds = {new AlgorithmId(AlgorithmId.SHA256_oid)}; + + X509Certificate[] certs = {signer3.getCert(), signer2.getCert(), + signer1.getCert()}; + + PKCS7 pkcs71 = new PKCS7(algIds, contentInfo, + certs, + signerInfos); + + System.out.println("SignerInfos in original."); + printSignerInfos(pkcs71.getSignerInfos()); + + DerOutputStream out = new DerOutputStream(); + pkcs71.encodeSignedData(out); + + PKCS7 pkcs72 = new PKCS7(out.toByteArray()); + System.out.println("\nSignerInfos read back in:"); + printSignerInfos(pkcs72.getSignerInfos()); + + System.out.println("Verified signers of original:"); + SignerInfo[] verifs1 = pkcs71.verify(); + + System.out.println("Verified signers of after read-in:"); + SignerInfo[] verifs2 = pkcs72.verify(); + + if (verifs1.length != verifs2.length) { + throw new RuntimeException("Length or Original vs read-in " + + "should be same"); + } + } + + static void printSignerInfos(SignerInfo signerInfo) throws IOException { + ByteArrayOutputStream strm = new ByteArrayOutputStream(); + signerInfo.derEncode(strm); + System.out.println("SignerInfo, length: " + + strm.toByteArray().length); + System.out.println(hexDump.encode(strm.toByteArray())); + System.out.println("\n"); + strm.reset(); + } + + static void printSignerInfos(SignerInfo[] signerInfos) throws IOException { + ByteArrayOutputStream strm = new ByteArrayOutputStream(); + for (int i = 0; i < signerInfos.length; i++) { + signerInfos[i].derEncode(strm); + System.out.println("SignerInfo[" + i + "], length: " + + strm.toByteArray().length); + System.out.println(hexDump.encode(strm.toByteArray())); + System.out.println("\n"); + strm.reset(); + } + } + +} + +/** + * A simple extension of sun.security.x509.X500Signer that adds a no-fuss + * signing algorithm. + */ +class SimpleSigner { + + private final Signature sig; + private final X500Name agent; + private final AlgorithmId digestAlgId; + private final AlgorithmId encryptionAlgId; + private final AlgorithmId algId; // signature algid; + //combines digest + encryption + private final X509Key publicKey; + private final PrivateKey privateKey; + private final X509Certificate cert; + + public SimpleSigner(String digestAlg, + String encryptionAlg, + KeyPair keyPair, + X500Name agent) throws Exception { + + if (agent == null) { + agent = new X500Name("cn=test"); + } + if (digestAlg == null) { + digestAlg = "SHA"; + } + if (encryptionAlg == null) { + encryptionAlg = "DSA"; + } + if (keyPair == null) { + KeyPairGenerator keyGen = + KeyPairGenerator.getInstance(encryptionAlg); + keyGen.initialize(1024); + keyPair = keyGen.generateKeyPair(); + } + publicKey = (X509Key) keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + + if ("DSA".equals(encryptionAlg)) { + this.sig = Signature.getInstance(encryptionAlg); + } else { // RSA + this.sig = Signature.getInstance(digestAlg + "/" + encryptionAlg); + } + this.sig.initSign(privateKey); + + this.agent = agent; + this.digestAlgId = AlgorithmId.get(digestAlg); + this.encryptionAlgId = AlgorithmId.get(encryptionAlg); + this.algId = AlgorithmId.get(this.sig.getAlgorithm()); + + this.cert = getSelfCert(); + } + + /** + * Take the data and sign it. + * + * @param buf buffer holding the next chunk of the data to be signed + * @param offset starting point of to-be-signed data + * @param len how many bytes of data are to be signed + * @return the signature for the input data. + * @exception SignatureException on errors. + */ + public byte[] simpleSign(byte[] buf, int offset, int len) + throws SignatureException { + sig.update(buf, offset, len); + return sig.sign(); + } + + /** + * Returns the digest algorithm used to sign. + */ + public AlgorithmId getDigestAlgId() { + return digestAlgId; + } + + /** + * Returns the encryption algorithm used to sign. + */ + public AlgorithmId getEncryptionAlgId() { + return encryptionAlgId; + } + + /** + * Returns the name of the signing agent. + */ + public X500Name getSigner() { + return agent; + } + + public X509Certificate getCert() { + return cert; + } + + private X509Certificate getSelfCert() throws Exception { + long validity = 1000; + X509CertImpl certLocal; + Date firstDate, lastDate; + + firstDate = new Date(); + lastDate = new Date(); + lastDate.setTime(lastDate.getTime() + validity + 1000); + + CertificateValidity interval = new CertificateValidity(firstDate, + lastDate); + + X509CertInfo info = new X509CertInfo(); + // Add all mandatory attributes + info.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V1)); + info.set(X509CertInfo.SERIAL_NUMBER, + new CertificateSerialNumber( + (int) (firstDate.getTime() / 1000))); + info.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(algId)); + info.set(X509CertInfo.SUBJECT, agent); + info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); + info.set(X509CertInfo.VALIDITY, interval); + info.set(X509CertInfo.ISSUER, agent); + + certLocal = new X509CertImpl(info); + certLocal.sign(privateKey, algId.getName()); + + return certLocal; + } + + public SignerInfo genSignerInfo(byte[] data) throws SignatureException { + return new SignerInfo((X500Name) cert.getIssuerDN(), + new BigInteger("" + cert.getSerialNumber()), + getDigestAlgId(), algId, + simpleSign(data, 0, data.length)); + } +} diff --git a/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/MANIFEST.MF b/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..6be546d4daf36ee6bb5146cf09e3cc10583c69d7 --- /dev/null +++ b/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/MANIFEST.MF @@ -0,0 +1,82 @@ +Manifest-Version: 1.0 + +Name: CheckCerts.class +Digest-Algorithms: SHA +SHA-Digest: xLygljhRro6990piIVEilVI8szQ= + +Name: ContentInfoTest.class +Digest-Algorithms: SHA +SHA-Digest: TSVdEMQW2gdFi6qeba+UixdHSdo= + +Name: JarVerify.class +Digest-Algorithms: SHA +SHA-Digest: Wg+PiDzunNGH4KrWAp00/okp39s= + +Name: JarVerify2.class +Digest-Algorithms: SHA +SHA-Digest: 5uYBQxwGWgYmNBwhnWRbymeXmWM= + +Name: PKCS7Read.class +Digest-Algorithms: SHA +SHA-Digest: JPIxttHBfRpQaFyiQJ2Wfkvj/ls= + +Name: PKCS7Test.class +Digest-Algorithms: SHA +SHA-Digest: R64SXXgZrOvGiO/eMsfG/T1Vn30= + +Name: PKCS7Test10.class +Digest-Algorithms: SHA +SHA-Digest: 2R0yxuxRHTPqdAzJJcrvqkpbQgo= + +Name: PKCS7Test11.class +Digest-Algorithms: SHA +SHA-Digest: /0HcwnpQi0hwJsJtvt5peWFGvtc= + +Name: PKCS7Test12.class +Digest-Algorithms: SHA +SHA-Digest: s5CcqimfRqR9CW25tFBY0JK3RVU= + +Name: PKCS7Test2.class +Digest-Algorithms: SHA +SHA-Digest: 71VkFEMUle5sjXNFbSW31F1ZJ58= + +Name: PKCS7Test3.class +Digest-Algorithms: SHA +SHA-Digest: mU/D5C6SgPRmwoLQzwF5VnN3aqM= + +Name: PKCS7Test4.class +Digest-Algorithms: SHA +SHA-Digest: ss9NFvxF8emaEjdKdvtzWXfs0/E= + +Name: PKCS7Test5.class +Digest-Algorithms: SHA +SHA-Digest: DHvQ20UAXoYgfCPAOeCOrglsJwU= + +Name: PKCS7Test6.class +Digest-Algorithms: SHA +SHA-Digest: aiCb8chroH7XDaNfAz6wr57lXsA= + +Name: PKCS7Test7.class +Digest-Algorithms: SHA +SHA-Digest: UoieXLC68alFgfD/Q1NW9/r2kaY= + +Name: PKCS7Test8.class +Digest-Algorithms: SHA +SHA-Digest: eMW7mq5b/KVB1M5L76wcV1+uFQs= + +Name: PKCS7Test9.class +Digest-Algorithms: SHA +SHA-Digest: EEWCZG1creWjqVZVIEgr0on3y6A= + +Name: SignerInfoTest.class +Digest-Algorithms: SHA +SHA-Digest: l6SNfpnFipGg8gy4XqY3HhA0RrY= + +Name: SignerInfoTest2.class +Digest-Algorithms: SHA +SHA-Digest: 5jbzlkZqXKNmmmE+pcjQka8D6WE= + +Name: SimpleSigner.class +Digest-Algorithms: SHA +SHA-Digest: l9ODQHY4wxhIvLw4/B0qe9NjwxQ= + diff --git a/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.DSA.base64 b/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.DSA.base64 new file mode 100644 index 0000000000000000000000000000000000000000..f084beb89b674a30516f6693cc927dea9140bb1c --- /dev/null +++ b/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.DSA.base64 @@ -0,0 +1,60 @@ +MIILKAYJKoZIhvcNAQcCoIILGTCCCxUCAQExCzAJBgUrDgMCGgUAMIIHbQYJKoZI +hvcNAQcBoIIHXgSCB1pTaWduYXR1cmUtVmVyc2lvbjogMS4wDQoNCk5hbWU6IENo +ZWNrQ2VydHMuY2xhc3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdl +c3Q6IHlhMXh3dnNRTytEUnBRYnczRmgyblJCMkpRYz0NCg0KTmFtZTogQ29udGVu +dEluZm9UZXN0LmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGln +ZXN0OiBDYStFSmFrVTZ6dzRLQWhvcWNuQ3BOcWsyTEk9DQoNCk5hbWU6IEphclZl +cmlmeS5jbGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDog +K0RHYVdXa25md2U0Wk9wc29NVEZ6ZldSdmhRPQ0KDQpOYW1lOiBKYXJWZXJpZnky +LmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGlnZXN0OiBHcUR6 +WXlZNFAvV0g1SEt2aVdxWHR0UGc1ckU9DQoNCk5hbWU6IFBLQ1M3UmVhZC5jbGFz +cw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDogUW1mOEs5aFhW +bHdJZFBZNm52MmpGUGZHcWtBPQ0KDQpOYW1lOiBQS0NTN1Rlc3QuY2xhc3MNCkRp +Z2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IEdiZS9nenl2MkY1OGY2 +RUVoU1oxQnFHWHRsbz0NCg0KTmFtZTogUEtDUzdUZXN0MTAuY2xhc3MNCkRpZ2Vz +dC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IDh3QnFXLy9lVzJzTlJJOTFi +TFlFT29kY2dhRT0NCg0KTmFtZTogUEtDUzdUZXN0MTEuY2xhc3MNCkRpZ2VzdC1B +bGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IGJYaExLRXNsY3VFWGk0dS9haGdU +MnE2dGNFVT0NCg0KTmFtZTogUEtDUzdUZXN0MTIuY2xhc3MNCkRpZ2VzdC1BbGdv +cml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IDlLRVkxYjUyUUxtTjBxei81ejB3QkZy +T216MD0NCg0KTmFtZTogUEtDUzdUZXN0Mi5jbGFzcw0KRGlnZXN0LUFsZ29yaXRo +bXM6IFNIQQ0KU0hBLURpZ2VzdDogK1VhMzIvMlE4RjJiclFRbVNYWCtYUytNL2g0 +PQ0KDQpOYW1lOiBQS0NTN1Rlc3QzLmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczog +U0hBDQpTSEEtRGlnZXN0OiAwSFhVWnlhU2ZkZUtlZThuWnpFalJTeXJldTQ9DQoN +Ck5hbWU6IFBLQ1M3VGVzdDQuY2xhc3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEEN +ClNIQS1EaWdlc3Q6IEo3eXJTMjRvS3VTZ2F1dHZkemhxQmo3ZGJjUT0NCg0KTmFt +ZTogUEtDUzdUZXN0NS5jbGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hB +LURpZ2VzdDogSlR2OVdTb3gxTEVTUjJMcTdzMFVxU2x0RFNRPQ0KDQpOYW1lOiBQ +S0NTN1Rlc3Q2LmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGln +ZXN0OiBnR3Yra05oK3UzSFExdHp4bGNBVzdTcEZUS2s9DQoNCk5hbWU6IFBLQ1M3 +VGVzdDcuY2xhc3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6 +IGZpSEYxYUExYWN6czFPd0V5OEc3VkMrcjdMST0NCg0KTmFtZTogUEtDUzdUZXN0 +OC5jbGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDogNzRU +VzdJOVZPdzVWZ0x2aFJtRGZxRVd2ZkFRPQ0KDQpOYW1lOiBQS0NTN1Rlc3Q5LmNs +YXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGlnZXN0OiAxY0JJbkdU +Y08xQVFaKy8wdmhGa2laV3dsQTA9DQoNCk5hbWU6IFNpZ25lckluZm9UZXN0LmNs +YXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGlnZXN0OiBjRlk0Q3RT +anphMUErV2pBS05TVnF1cGpSWUU9DQoNCk5hbWU6IFNpZ25lckluZm9UZXN0Mi5j +bGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDogYU5NMEZQ +MHpFelF6eGxYeDZxQ0J4dWtta0hRPQ0KDQpOYW1lOiBTaW1wbGVTaWduZXIuY2xh +c3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IC9MV0NzbkM3 +TVpNUjZHb3czeTJjdnA3STBTTT0NCg0KoIICvzCCArswggJ3AgUA59UzNDALBgcq +hkjOOAQDBQAwdTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlD +dXBlcnRpbm8xGTAXBgNVBAoTEFN1biBNaWNyb3N5c3RlbXMxETAPBgNVBAsTCEph +dmFTb2Z0MRcwFQYDVQQDEw5Eb3VnbGFzIEhvb3ZlcjAeFw05NzEwMDIxODEyMDda +Fw05NzEyMzExNzEyMDdaMHUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAG +A1UEBxMJQ3VwZXJ0aW5vMRkwFwYDVQQKExBTdW4gTWljcm9zeXN0ZW1zMREwDwYD +VQQLEwhKYXZhU29mdDEXMBUGA1UEAxMORG91Z2xhcyBIb292ZXIwggFRMIHoBgcq +hkjOOAQBMIHcAmEA6eZCWZ01XzfJf/01ZxILjiXJzUPpJ7OpZw++xdiQFBki0sOz +rSSACTeZhp0ehGqrSfqwrSbSzmoiIZ1HC859d31KIfvpwnC1f2BwAvPO+Dk2lM9F +7jaIwRqMVqsSej2vAhUAnNvYTJ8awvOND4D0KrlS5zOL9RECYDBHCtWgBfsUzi2d +zYfji8fRscX6y67L6V8ZCqejHSPE27y+BhdFREAaWywCCWXYwr0hcdNmhEV3H3S6 +CE0gKdg8HBWFR/Op8aJxW+I9Ua5NPlofanBk8xaTOjRtP1KSUgNkAAJhAMN5uB+B +ZJ0W2UjXMyKoFUFXRYiLpnaSw63kl9tKnR9R5rEreiyHQ5IelPxjwCHGgTbYK0y+ +xKTGHVWiQN/YJmHLbSrcSSM/d89aR/sVbGoAwQOyYraFGUNIOTQjjXcXCjALBgcq +hkjOOAQDBQADMQAwLgIVAJxmL029GLXDJVbk72d4cSPQ4/rvAhUAll9UPl8aOMEg +V4egANhwbynMGSgxgc4wgcsCAQEwfjB1MQswCQYDVQQGEwJVUzELMAkGA1UECBMC +Q0ExEjAQBgNVBAcTCUN1cGVydGlubzEZMBcGA1UEChMQU3VuIE1pY3Jvc3lzdGVt +czERMA8GA1UECxMISmF2YVNvZnQxFzAVBgNVBAMTDkRvdWdsYXMgSG9vdmVyAgUA +59UzNDAJBgUrDgMCGgUAMAsGByqGSM44BAMFAAQuMCwCFDmry17kzDD6Y5X1BqIS +lq6swckPAhRtiXvBHa5CRGjbwk8yqf9hGgZfFA== diff --git a/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.SF b/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.SF new file mode 100644 index 0000000000000000000000000000000000000000..05a793821897da6c23a8f8d3f68bf5f858190d00 --- /dev/null +++ b/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.SF @@ -0,0 +1,82 @@ +Signature-Version: 1.0 + +Name: CheckCerts.class +Digest-Algorithms: SHA +SHA-Digest: ya1xwvsQO+DRpQbw3Fh2nRB2JQc= + +Name: ContentInfoTest.class +Digest-Algorithms: SHA +SHA-Digest: Ca+EJakU6zw4KAhoqcnCpNqk2LI= + +Name: JarVerify.class +Digest-Algorithms: SHA +SHA-Digest: +DGaWWknfwe4ZOpsoMTFzfWRvhQ= + +Name: JarVerify2.class +Digest-Algorithms: SHA +SHA-Digest: GqDzYyY4P/WH5HKviWqXttPg5rE= + +Name: PKCS7Read.class +Digest-Algorithms: SHA +SHA-Digest: Qmf8K9hXVlwIdPY6nv2jFPfGqkA= + +Name: PKCS7Test.class +Digest-Algorithms: SHA +SHA-Digest: Gbe/gzyv2F58f6EEhSZ1BqGXtlo= + +Name: PKCS7Test10.class +Digest-Algorithms: SHA +SHA-Digest: 8wBqW//eW2sNRI91bLYEOodcgaE= + +Name: PKCS7Test11.class +Digest-Algorithms: SHA +SHA-Digest: bXhLKEslcuEXi4u/ahgT2q6tcEU= + +Name: PKCS7Test12.class +Digest-Algorithms: SHA +SHA-Digest: 9KEY1b52QLmN0qz/5z0wBFrOmz0= + +Name: PKCS7Test2.class +Digest-Algorithms: SHA +SHA-Digest: +Ua32/2Q8F2brQQmSXX+XS+M/h4= + +Name: PKCS7Test3.class +Digest-Algorithms: SHA +SHA-Digest: 0HXUZyaSfdeKee8nZzEjRSyreu4= + +Name: PKCS7Test4.class +Digest-Algorithms: SHA +SHA-Digest: J7yrS24oKuSgautvdzhqBj7dbcQ= + +Name: PKCS7Test5.class +Digest-Algorithms: SHA +SHA-Digest: JTv9WSox1LESR2Lq7s0UqSltDSQ= + +Name: PKCS7Test6.class +Digest-Algorithms: SHA +SHA-Digest: gGv+kNh+u3HQ1tzxlcAW7SpFTKk= + +Name: PKCS7Test7.class +Digest-Algorithms: SHA +SHA-Digest: fiHF1aA1aczs1OwEy8G7VC+r7LI= + +Name: PKCS7Test8.class +Digest-Algorithms: SHA +SHA-Digest: 74TW7I9VOw5VgLvhRmDfqEWvfAQ= + +Name: PKCS7Test9.class +Digest-Algorithms: SHA +SHA-Digest: 1cBInGTcO1AQZ+/0vhFkiZWwlA0= + +Name: SignerInfoTest.class +Digest-Algorithms: SHA +SHA-Digest: cFY4CtSjza1A+WjAKNSVqupjRYE= + +Name: SignerInfoTest2.class +Digest-Algorithms: SHA +SHA-Digest: aNM0FP0zEzQzxlXx6qCBxukmkHQ= + +Name: SimpleSigner.class +Digest-Algorithms: SHA +SHA-Digest: /LWCsnC7MZMR6Gow3y2cvp7I0SM= + diff --git a/test/sun/security/pkcs/pkcs8/PKCS8Test.java b/test/sun/security/pkcs/pkcs8/PKCS8Test.java new file mode 100644 index 0000000000000000000000000000000000000000..6bd3af5b96c98ce2ee39166000a7ceec96a6b49d --- /dev/null +++ b/test/sun/security/pkcs/pkcs8/PKCS8Test.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/* + * @test + * @bug 8048357 + * @summary PKCS8 Standards Conformance Tests + * @requires (os.family != "solaris") + * @compile -XDignore.symbol.file PKCS8Test.java + * @run main PKCS8Test + */ + +/* + * Skip Solaris since the DSAPrivateKeys returned by + * SunPKCS11 Provider are not subclasses of PKCS8Key + */ +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.Arrays; +import sun.misc.HexDumpEncoder; +import sun.security.pkcs.PKCS8Key; +import sun.security.provider.DSAPrivateKey; +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; +import sun.security.x509.AlgorithmId; +import static java.lang.System.out; + +public class PKCS8Test { + + static final HexDumpEncoder hexDump = new HexDumpEncoder(); + + static final DerOutputStream derOutput = new DerOutputStream(); + + static final String FORMAT = "PKCS#8"; + static final String EXPECTED_ALG_ID_CHRS = "DSA\n\tp: 02\n\tq: 03\n" + + "\tg: 04\n"; + static final String ALGORITHM = "DSA"; + static final String EXCEPTION_MESSAGE = "version mismatch: (supported: " + + "00, parsed: 01"; + + // test second branch in byte[] encode() + // DER encoding,include (empty) set of attributes + static final int[] NEW_ENCODED_KEY_INTS = { 0x30, + // length 30 = 0x1e + 0x1e, + // first element + // version Version (= INTEGER) + 0x02, + // length 1 + 0x01, + // value 0 + 0x00, + // second element + // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier + // (sequence) + // (an object identifier?) + 0x30, + // length 18 + 0x12, + // contents + // object identifier, 5 bytes + 0x06, 0x05, + // { 1 3 14 3 2 12 } + 0x2b, 0x0e, 0x03, 0x02, 0x0c, + // sequence, 9 bytes + 0x30, 0x09, + // integer 2 + 0x02, 0x01, 0x02, + // integer 3 + 0x02, 0x01, 0x03, + // integer 4 + 0x02, 0x01, 0x04, + // third element + // privateKey PrivateKey (= OCTET STRING) + 0x04, + // length + 0x03, + // privateKey contents + 0x02, 0x01, 0x01, + // 4th (optional) element -- attributes [0] IMPLICIT Attributes + // OPTIONAL + // (Attributes = SET OF Attribute) Here, it will be empty. + 0xA0, + // length + 0x00 }; + + // encoding originally created, but with the version changed + static final int[] NEW_ENCODED_KEY_INTS_2 = { + // sequence + 0x30, + // length 28 = 0x1c + 0x1c, + // first element + // version Version (= INTEGER) + 0x02, + // length 1 + 0x01, + // value 1 (illegal) + 0x01, + // second element + // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier + // (sequence) + // (an object identifier?) + 0x30, + // length 18 + 0x12, + // contents + // object identifier, 5 bytes + 0x06, 0x05, + // { 1 3 14 3 2 12 } + 0x2b, 0x0e, 0x03, 0x02, 0x0c, + // sequence, 9 bytes + 0x30, 0x09, + // integer 2 + 0x02, 0x01, 0x02, + // integer 3 + 0x02, 0x01, 0x03, + // integer 4 + 0x02, 0x01, 0x04, + // third element + // privateKey PrivateKey (= OCTET STRING) + 0x04, + // length + 0x03, + // privateKey contents + 0x02, 0x01, 0x01 }; + + // 0000: 30 1E 02 01 00 30 14 06 07 2A 86 48 CE 38 04 01 0....0...*.H.8.. + // 0010: 30 09 02 01 02 02 01 03 02 01 04 04 03 02 01 01 0............... + static final int[] EXPECTED = { 0x30, + // length 30 = 0x1e + 0x1e, + // first element + // version Version (= INTEGER) + 0x02, + // length 1 + 0x01, + // value 0 + 0x00, + // second element + // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier + // (sequence) + // (an object identifier?) + 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01, + // integer 2 + 0x30, 0x09, 0x02, + // integer 3 + 0x01, 0x02, 0x02, + // integer 4 + 0x01, 0x03, 0x02, + // third element + // privateKey PrivateKey (= OCTET STRING) + 0x01, + // length + 0x04, + // privateKey contents + 0x04, 0x03, 0x02, + // 4th (optional) element -- attributes [0] IMPLICIT Attributes + // OPTIONAL + // (Attributes = SET OF Attribute) Here, it will be empty. + 0x01, + // length + 0x01 }; + + static void raiseException(String expected, String received) { + throw new RuntimeException( + "Expected " + expected + "; Received " + received); + } + + public static void main(String[] args) + throws IOException, InvalidKeyException { + + BigInteger p = BigInteger.valueOf(1); + BigInteger q = BigInteger.valueOf(2); + BigInteger g = BigInteger.valueOf(3); + BigInteger x = BigInteger.valueOf(4); + + DSAPrivateKey priv = new DSAPrivateKey(p, q, g, x); + + byte[] encodedKey = priv.getEncoded(); + byte[] expectedBytes = new byte[EXPECTED.length]; + for (int i = 0; i < EXPECTED.length; i++) { + expectedBytes[i] = (byte) EXPECTED[i]; + } + + dumpByteArray("encodedKey :", encodedKey); + if (!Arrays.equals(encodedKey, expectedBytes)) { + raiseException(new String(expectedBytes), new String(encodedKey)); + } + + PKCS8Key decodedKey = PKCS8Key.parse(new DerValue(encodedKey)); + + String alg = decodedKey.getAlgorithm(); + AlgorithmId algId = decodedKey.getAlgorithmId(); + out.println("Algorithm :" + alg); + out.println("AlgorithmId: " + algId); + + if (!ALGORITHM.equals(alg)) { + raiseException(ALGORITHM, alg); + } + if (!EXPECTED_ALG_ID_CHRS.equalsIgnoreCase(algId.toString())) { + raiseException(EXPECTED_ALG_ID_CHRS, algId.toString()); + } + + decodedKey.encode(derOutput); + dumpByteArray("Stream encode: ", derOutput.toByteArray()); + if (!Arrays.equals(derOutput.toByteArray(), expectedBytes)) { + raiseException(new String(expectedBytes), derOutput.toString()); + } + + dumpByteArray("byte[] encoding: ", decodedKey.getEncoded()); + if (!Arrays.equals(decodedKey.getEncoded(), expectedBytes)) { + raiseException(new String(expectedBytes), + new String(decodedKey.getEncoded())); + } + + if (!FORMAT.equals(decodedKey.getFormat())) { + raiseException(FORMAT, decodedKey.getFormat()); + } + + try { + byte[] newEncodedKey = new byte[NEW_ENCODED_KEY_INTS.length]; + for (int i = 0; i < newEncodedKey.length; i++) { + newEncodedKey[i] = (byte) NEW_ENCODED_KEY_INTS[i]; + } + PKCS8Key newDecodedKey = PKCS8Key + .parse(new DerValue(newEncodedKey)); + + throw new RuntimeException( + "key1: Expected an IOException during " + "parsing"); + } catch (IOException e) { + System.out.println("newEncodedKey: should have excess data due to " + + "attributes, which are not supported"); + } + + try { + byte[] newEncodedKey2 = new byte[NEW_ENCODED_KEY_INTS_2.length]; + for (int i = 0; i < newEncodedKey2.length; i++) { + newEncodedKey2[i] = (byte) NEW_ENCODED_KEY_INTS_2[i]; + } + + PKCS8Key newDecodedKey2 = PKCS8Key + .parse(new DerValue(newEncodedKey2)); + + throw new RuntimeException( + "key2: Expected an IOException during " + "parsing"); + } catch (IOException e) { + out.println("Key 2: should be illegal version"); + out.println(e.getMessage()); + if (!EXCEPTION_MESSAGE.equals(e.getMessage())) { + throw new RuntimeException("Key2: expected: " + + EXCEPTION_MESSAGE + " get: " + e.getMessage()); + } + } + } + + static void dumpByteArray(String nm, byte[] bytes) throws IOException { + out.println(nm + " length: " + bytes.length); + hexDump.encodeBuffer(bytes, out); + } +} diff --git a/test/sun/security/pkcs11/Mac/MacKAT.java b/test/sun/security/pkcs11/Mac/MacKAT.java new file mode 100644 index 0000000000000000000000000000000000000000..c7da92971591301d1e295a3608ecc9c0317466c8 --- /dev/null +++ b/test/sun/security/pkcs11/Mac/MacKAT.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.io.UnsupportedEncodingException; +import java.security.Provider; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +/** + * @test + * @bug 4846410 6313661 4963723 + * @summary Basic known-answer-test for Hmac algorithms + * @author Andreas Sterbenz + * @library .. + * @run main MacKAT + */ +public class MacKAT extends PKCS11Test { + + private final static byte[] ALONG, BLONG, BKEY, BKEY_20, DDDATA_50, + AAKEY_20, CDDATA_50, AAKEY_131; + + static { + ALONG = new byte[1024 * 128]; + Arrays.fill(ALONG, (byte)'a'); + BLONG = new byte[1024 * 128]; + Random random = new Random(12345678); + random.nextBytes(BLONG); + BKEY = new byte[128]; + random.nextBytes(BKEY); + BKEY_20 = new byte[20]; + Arrays.fill(BKEY_20, (byte) 0x0b); + DDDATA_50 = new byte[50]; + Arrays.fill(DDDATA_50, (byte) 0xdd); + AAKEY_20 = new byte[20]; + Arrays.fill(AAKEY_20, (byte) 0xaa); + CDDATA_50 = new byte[50]; + Arrays.fill(CDDATA_50, (byte) 0xcd); + AAKEY_131 = new byte[131]; + Arrays.fill(AAKEY_131, (byte) 0xaa); + } + + private final static Test[] tests = { + newMacTest("SslMacMD5", + ALONG, + "f4:ad:01:71:51:f6:89:56:72:a3:32:bf:d9:2a:f2:a5", + "1b:34:61:29:05:0d:73:db:25:d0:dd:64:06:29:f6:8a"), + newMacTest("SslMacMD5", + BLONG, + "34:1c:ad:a0:95:57:32:f8:8e:80:8f:ee:b2:d8:23:e5", + "76:00:4a:72:98:9b:65:ec:2e:f1:43:c4:65:4a:13:71"), + newMacTest("SslMacSHA1", + ALONG, + "11:c1:71:2e:61:be:4b:cf:bc:6d:e2:4c:58:ae:27:30:0b:24:a4:87", + "23:ae:dd:61:87:6c:7a:45:47:2f:2c:8f:ea:64:99:3e:27:5f:97:a5"), + newMacTest("SslMacSHA1", + BLONG, + "84:af:57:0a:af:ef:16:93:90:50:da:88:f8:ad:1a:c5:66:6c:94:d0", + "9b:bb:e2:aa:9b:28:1c:95:0e:ea:30:21:98:a5:7e:31:9e:bf:5f:51"), + newMacTest("HmacMD5", + ALONG, + "76:00:4a:72:98:9b:65:ec:2e:f1:43:c4:65:4a:13:71", + "1b:34:61:29:05:0d:73:db:25:d0:dd:64:06:29:f6:8a"), + newMacTest("HmacMD5", + BLONG, + "6c:22:79:bb:34:9e:da:f4:f5:cf:df:0c:62:3d:59:e0", + "76:00:4a:72:98:9b:65:ec:2e:f1:43:c4:65:4a:13:71"), + newMacTest("HmacMD5", + BLONG, + "e6:ad:00:c9:49:6b:98:fe:53:a2:b9:2d:7d:41:a2:03", + BKEY), + newMacTest("HmacSHA1", + ALONG, + "9e:b3:6e:35:fa:fb:17:2e:2b:f3:b0:4a:9d:38:83:c4:5f:6d:d9:00", + "1b:34:61:29:05:0d:73:db:25:d0:dd:64:06:29:f6:8a"), + newMacTest("HmacSHA1", + BLONG, + "80:2d:5b:ea:08:df:a4:1f:e5:3e:1c:fa:fc:ad:dd:31:da:15:60:2c", + "76:00:4a:72:98:9b:65:ec:2e:f1:43:c4:65:4a:13:71"), + newMacTest("HmacSHA1", + BLONG, + "a2:fa:2a:85:18:0e:94:b2:a5:e2:17:8b:2a:29:7a:95:cd:e8:aa:82", + BKEY), + newMacTest("HmacSHA256", + ALONG, + "3f:6d:08:df:0c:90:b0:e9:ed:13:4a:2e:c3:48:1d:3d:3e:61:2e:f1:" + + "30:c2:63:c4:58:57:03:c2:cb:87:15:07", + "1b:34:61:29:05:0d:73:db:25:d0:dd:64:06:29:f6:8a"), + newMacTest("HmacSHA256", + BLONG, + "e2:4e:a3:b9:0b:b8:99:e4:71:cf:ca:9f:f8:4e:f0:34:8b:19:9f:33:" + + "4b:1a:b7:13:f7:c8:57:92:e3:03:74:78", + BKEY), + newMacTest("HmacSHA384", + ALONG, + "d0:f0:d4:54:1c:0a:6d:81:ed:15:20:d7:0c:96:06:61:a0:ff:c9:ff:" + + "91:e9:a0:cd:e2:45:64:9d:93:4c:a9:fa:89:ae:c0:90:e6:" + + "0b:a1:a0:56:80:57:3b:ed:4b:b0:71", + "1b:34:61:29:05:0d:73:db:25:d0:dd:64:06:29:f6:8a"), + newMacTest("HmacSHA384", + BLONG, + "75:c4:ca:c7:f7:58:9d:d3:23:b1:1b:5c:93:2d:ec:7a:03:dc:8c:eb:" + + "8d:fe:79:46:4f:30:e7:99:62:de:44:e2:38:95:0e:79:91:" + + "78:2f:a4:05:0a:f0:17:10:38:a1:8e", + BKEY), + newMacTest("HmacSHA512", + ALONG, + "41:ea:4c:e5:31:3f:7c:18:0e:5e:95:a9:25:0a:10:58:e6:40:53:88:" + + "82:4f:5a:da:6f:29:de:04:7b:8e:d7:ed:7c:4d:b8:2a:48:" + + "2d:17:2a:2d:59:bb:81:9c:bf:33:40:04:77:44:fb:45:25:" + + "1f:fd:b9:29:f4:a6:69:a3:43:6f", + "1b:34:61:29:05:0d:73:db:25:d0:dd:64:06:29:f6:8a"), + newMacTest("HmacSHA512", + BLONG, + "fb:cf:4b:c6:d5:49:5a:5b:0b:d9:2a:32:f5:fa:68:d2:68:a4:0f:ae:" + + "53:fc:49:12:e6:1d:53:cf:b2:cb:c5:c5:f2:2d:86:bd:14:" + + "61:30:c3:a6:6f:44:1f:77:9b:aa:a1:22:48:a9:dd:d0:45:" + + "86:d1:a1:82:53:13:c4:03:06:a3", + BKEY), + + // Test vectors From RFC 4231 + newMacTest("HmacSHA224", + bytes("Hi There"), + "89:6f:b1:12:8a:bb:df:19:68:32:10:7c:d4:9d:f3:3f:47:b4:b1:16:" + + "99:12:ba:4f:53:68:4b:22", + BKEY_20), + newMacTest("HmacSHA224", + bytes("what do ya want for nothing?"), + "a3:0e:01:09:8b:c6:db:bf:45:69:0f:3a:7e:9e:6d:0f:8b:be:a2:a3:" + + "9e:61:48:00:8f:d0:5e:44", + bytes("Jefe")), + newMacTest("HmacSHA224", + DDDATA_50, + "7f:b3:cb:35:88:c6:c1:f6:ff:a9:69:4d:7d:6a:d2:64:93:65:b0:c1:" + + "f6:5d:69:d1:ec:83:33:ea", + AAKEY_20), + newMacTest("HmacSHA224", + CDDATA_50, + "6c:11:50:68:74:01:3c:ac:6a:2a:bc:1b:b3:82:62:7c:ec:6a:90:d8:" + + "6e:fc:01:2d:e7:af:ec:5a", + "01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:" + + "15:16:17:18:19"), + newMacTest("HmacSHA224", + bytes("Test Using Larger Than Block-Size Key - Hash Key First"), + "95:e9:a0:db:96:20:95:ad:ae:be:9b:2d:6f:0d:bc:e2:d4:99:f1:12:" + + "f2:d2:b7:27:3f:a6:87:0e", + AAKEY_131), + newMacTest("HmacSHA224", + bytes("This is a test using a larger than block-size key and " + + "a larger than block-size data. The key needs to be " + + "hashed before being used by the HMAC algorithm."), + "3a:85:41:66:ac:5d:9f:02:3f:54:d5:17:d0:b3:9d:bd:94:67:70:db:" + + "9c:2b:95:c9:f6:f5:65:d1", + AAKEY_131), + }; + + public static void main(String[] args) throws Exception { + main(new MacKAT()); + } + + @Override + public void main(Provider p) throws Exception { + long start = System.currentTimeMillis(); + + List algorithms = getSupportedAlgorithms("Mac", "", p); + for (Test test : tests) { + if(!algorithms.contains(test.getAlg())) { + continue; + } + test.run(p); + } + + System.out.println("All tests passed"); + long stop = System.currentTimeMillis(); + System.out.println("Done (" + (stop - start) + " ms)."); + } + + private static byte[] bytes(String s) { + try { + return s.getBytes("UTF8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private static Test newMacTest(String alg, byte[] input, String macvalue, + String key) { + return new MacTest(alg, input, parse(macvalue), parse(key)); + } + + private static Test newMacTest(String alg, byte[] input, String macvalue, + byte[] key) { + return new MacTest(alg, input, parse(macvalue), key); + } + + interface Test { + void run(Provider p) throws Exception; + String getAlg(); + } + + static class MacTest implements Test { + private final String alg; + private final byte[] input; + private final byte[] macvalue; + private final byte[] key; + + MacTest(String alg, byte[] input, byte[] macvalue, byte[] key) { + this.alg = alg; + this.input = input; + this.macvalue = macvalue; + this.key = key; + } + + @Override + public String getAlg() { + return alg; + } + + @Override + public void run(Provider p) throws Exception { + Mac mac = Mac.getInstance(alg, p); + SecretKey keySpec = new SecretKeySpec(key, alg); + mac.init(keySpec); + mac.update(input); + byte[] macv = mac.doFinal(); + if (Arrays.equals(macvalue, macv) == false) { + System.out.println("Mac test for " + alg + " failed:"); + if (input.length < 256) { + System.out.println("input: " + + PKCS11Test.toString(input)); + } + System.out.println("key: " + PKCS11Test.toString(key)); + System.out.println("macvalue: " + + PKCS11Test.toString(macvalue)); + System.out.println("calculated: " + PKCS11Test.toString(macv)); + throw new Exception("Mac test for " + alg + " failed"); + } + System.out.println("passed: " + alg); + } + } + +} diff --git a/test/sun/security/pkcs11/Mac/MacSameTest.java b/test/sun/security/pkcs11/Mac/MacSameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f5e2787e609e78387911c47f4d9ddc4d983c899b --- /dev/null +++ b/test/sun/security/pkcs11/Mac/MacSameTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.SecureRandom; +import java.util.List; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +/** + * @test + * @bug 8048603 + * @summary Check if doFinal and update operation result in same Mac + * @author Yu-Ching Valerie Peng, Bill Situ, Alexander Fomin + * @library .. + * @run main MacSameTest + */ +public class MacSameTest extends PKCS11Test { + + private static final int MESSAGE_SIZE = 25; + private static final int OFFSET = 5; + private static final int KEY_SIZE = 70; + + /** + * Initialize a message, instantiate a Mac object, + * initialize the object with a SecretKey, + * feed the message into the Mac object + * all at once and get the output MAC as result1. + * Reset the Mac object, chop the message into three pieces, + * feed into the Mac object sequentially, and get the output MAC as result2. + * Finally, compare result1 and result2 and see if they are the same. + * + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + main(new MacSameTest()); + } + + @Override + public void main(Provider p) { + List algorithms = getSupportedAlgorithms("Mac", "Hmac", p); + boolean success = true; + for (String alg : algorithms) { + try { + doTest(alg, p); + } catch (Exception e) { + System.out.println("Unexpected exception: " + e); + e.printStackTrace(); + success = false; + } + } + + if (!success) { + throw new RuntimeException("Test failed"); + } + } + + private void doTest(String algo, Provider provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException { + System.out.println("Test " + algo); + Mac mac; + try { + mac = Mac.getInstance(algo, provider); + } catch (NoSuchAlgorithmException nsae) { + if ("SunPKCS11-Solaris".equals(provider.getName())) { + // depending on Solaris configuration, + // it can support HMAC or not with Mac + System.out.println("Expected NoSuchAlgorithmException thrown: " + + nsae); + return; + } + throw nsae; + } + + byte[] plain = new byte[MESSAGE_SIZE]; + for (int i = 0; i < MESSAGE_SIZE; i++) { + plain[i] = (byte) (i % 256); + } + + byte[] tail = new byte[plain.length - OFFSET]; + System.arraycopy(plain, OFFSET, tail, 0, tail.length); + + SecureRandom srdm = new SecureRandom(); + byte[] keyVal = new byte[KEY_SIZE]; + srdm.nextBytes(keyVal); + SecretKeySpec keySpec = new SecretKeySpec(keyVal, "HMAC"); + + mac.init(keySpec); + byte[] result1 = mac.doFinal(plain); + + mac.reset(); + mac.update(plain[0]); + mac.update(plain, 1, OFFSET - 1); + byte[] result2 = mac.doFinal(tail); + + if (!java.util.Arrays.equals(result1, result2)) { + throw new RuntimeException("result1 and result2 are not the same"); + } + } + +} diff --git a/test/sun/security/pkcs11/PKCS11Test.java b/test/sun/security/pkcs11/PKCS11Test.java index ca836f032b2b8239342721fa9c65f559155a3eb1..c8a147af5c025b8ccb155ee6fcd3d009a5f03c0e 100644 --- a/test/sun/security/pkcs11/PKCS11Test.java +++ b/test/sun/security/pkcs11/PKCS11Test.java @@ -578,4 +578,21 @@ public abstract class PKCS11Test { return r; } + /** + * Returns supported algorithms of specified type. + */ + static List getSupportedAlgorithms(String type, String alg, + Provider p) { + // prepare a list of supported algorithms + List algorithms = new ArrayList<>(); + Set services = p.getServices(); + for (Provider.Service service : services) { + if (service.getType().equals(type) + && service.getAlgorithm().startsWith(alg)) { + algorithms.add(service.getAlgorithm()); + } + } + return algorithms; + } + } diff --git a/test/sun/security/x509/X509CertImpl/V3Certificate.java b/test/sun/security/x509/X509CertImpl/V3Certificate.java new file mode 100644 index 0000000000000000000000000000000000000000..57e96de5a10c4aa933974af0561b77a8d7f957f2 --- /dev/null +++ b/test/sun/security/x509/X509CertImpl/V3Certificate.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import static java.lang.System.out; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; +import sun.misc.BASE64Encoder; +import sun.security.util.BitArray; +import sun.security.util.ObjectIdentifier; +import sun.security.x509.*; + +/** + * @test + * @bug 8049237 + * @summary This test generates V3 certificate with all the supported + * extensions. Writes back the generated certificate in to a file and checks for + * equality with the original certificate. + */ +public class V3Certificate { + + public static final String V3_FILE = "certV3"; + public static final String V3_B64_FILE = "certV3.b64"; + + public static void main(String[] args) throws IOException, + NoSuchAlgorithmException, InvalidKeyException, CertificateException, + NoSuchProviderException, SignatureException { + + boolean success = true; + + success &= test("RSA", "SHA256withRSA", 2048); + success &= test("DSA", "SHA256withDSA", 2048); + success &= test("EC", "SHA256withECDSA", 384); + + if (!success) { + throw new RuntimeException("At least one test case failed"); + } + } + + public static boolean test(String algorithm, String sigAlg, int keyLength) + throws IOException, + NoSuchAlgorithmException, + InvalidKeyException, + CertificateException, + NoSuchProviderException, + SignatureException { + + byte[] issuerId = {1, 2, 3, 4, 5}; + byte[] subjectId = {6, 7, 8, 9, 10}; + boolean testResult = true; + + // Subject and Issuer + X500Name subject = new X500Name("test", "Oracle", "Santa Clara", + "US"); + X500Name issuer = subject; + + // Generate keys and sign + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm); + keyGen.initialize(keyLength); + KeyPair pair = keyGen.generateKeyPair(); + PublicKey publicKey = pair.getPublic(); + PrivateKey privateKey = pair.getPrivate(); + MessageDigest md = MessageDigest.getInstance("SHA"); + byte[] keyId = md.digest(publicKey.getEncoded()); + + Signature signature = Signature.getInstance(sigAlg); + signature.initSign(privateKey); + + // Validity interval + Date firstDate = new Date(); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("PST")); + cal.set(2014, 03, 10, 12, 30, 30); + Date lastDate = cal.getTime(); + CertificateValidity interval = new CertificateValidity(firstDate, + lastDate); + + // Certificate Info + X509CertInfo cert = new X509CertInfo(); + + cert.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + cert.set(X509CertInfo.SERIAL_NUMBER, + new CertificateSerialNumber((int) (firstDate.getTime() / 1000))); + cert.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(AlgorithmId.get(sigAlg))); + cert.set(X509CertInfo.SUBJECT, subject); + cert.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); + cert.set(X509CertInfo.VALIDITY, interval); + cert.set(X509CertInfo.ISSUER, issuer); + + cert.set(X509CertInfo.ISSUER_ID, + new UniqueIdentity( + new BitArray(issuerId.length * 8 - 2, issuerId))); + cert.set(X509CertInfo.SUBJECT_ID, new UniqueIdentity(subjectId)); + + // Create Extensions + CertificateExtensions exts = new CertificateExtensions(); + + GeneralNameInterface mailInf = new RFC822Name("test@Oracle.com"); + GeneralName mail = new GeneralName(mailInf); + GeneralNameInterface dnsInf = new DNSName("Oracle.com"); + GeneralName dns = new GeneralName(dnsInf); + GeneralNameInterface uriInf = new URIName("http://www.Oracle.com"); + GeneralName uri = new GeneralName(uriInf); + + // localhost + byte[] address = new byte[]{127, 0, 0, 1}; + + GeneralNameInterface ipInf = new IPAddressName(address); + GeneralName ip = new GeneralName(ipInf); + int[] oidData = new int[]{1, 2, 3, 4}; + + GeneralNameInterface oidInf = new OIDName(new ObjectIdentifier(oidData)); + GeneralName oid = new GeneralName(oidInf); + + SubjectAlternativeNameExtension subjectName + = new SubjectAlternativeNameExtension(); + IssuerAlternativeNameExtension issuerName + = new IssuerAlternativeNameExtension(); + + GeneralNames subjectNames + = (GeneralNames) subjectName. + get(SubjectAlternativeNameExtension.SUBJECT_NAME); + + GeneralNames issuerNames + = (GeneralNames) issuerName. + get(IssuerAlternativeNameExtension.ISSUER_NAME); + + subjectNames.add(mail); + subjectNames.add(dns); + subjectNames.add(uri); + + issuerNames.add(ip); + issuerNames.add(oid); + + cal.set(2000, 11, 15, 12, 30, 30); + lastDate = cal.getTime(); + PrivateKeyUsageExtension pkusage + = new PrivateKeyUsageExtension(firstDate, lastDate); + + KeyUsageExtension usage = new KeyUsageExtension(); + usage.set(KeyUsageExtension.CRL_SIGN, true); + usage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true); + usage.set(KeyUsageExtension.NON_REPUDIATION, true); + + KeyIdentifier kid = new KeyIdentifier(keyId); + SerialNumber sn = new SerialNumber(42); + AuthorityKeyIdentifierExtension aki + = new AuthorityKeyIdentifierExtension(kid, subjectNames, sn); + + SubjectKeyIdentifierExtension ski + = new SubjectKeyIdentifierExtension(keyId); + + BasicConstraintsExtension cons + = new BasicConstraintsExtension(true, 10); + + PolicyConstraintsExtension pce = new PolicyConstraintsExtension(2, 4); + + exts.set(SubjectAlternativeNameExtension.NAME, subjectName); + exts.set(IssuerAlternativeNameExtension.NAME, issuerName); + exts.set(PrivateKeyUsageExtension.NAME, pkusage); + exts.set(KeyUsageExtension.NAME, usage); + exts.set(AuthorityKeyIdentifierExtension.NAME, aki); + exts.set(SubjectKeyIdentifierExtension.NAME, ski); + exts.set(BasicConstraintsExtension.NAME, cons); + exts.set(PolicyConstraintsExtension.NAME, pce); + cert.set(X509CertInfo.EXTENSIONS, exts); + + // Generate and sign X509CertImpl + X509CertImpl crt = new X509CertImpl(cert); + crt.sign(privateKey, sigAlg); + crt.verify(publicKey); + + try (FileOutputStream fos = new FileOutputStream(new File(V3_FILE)); + FileOutputStream fos_b64 + = new FileOutputStream(new File(V3_B64_FILE)); + PrintWriter pw = new PrintWriter(fos_b64)) { + crt.encode((OutputStream) fos); + fos.flush(); + + // Certificate boundaries/ + pw.println("-----BEGIN CERTIFICATE-----"); + pw.flush(); + new BASE64Encoder().encodeBuffer(crt.getEncoded(), fos_b64); + fos_b64.flush(); + pw.println("-----END CERTIFICATE-----"); + } + + out.println("*** Certificate ***"); + out.println(crt); + out.println("*** End Certificate ***"); + + X509Certificate x2 = generateCertificate(V3_FILE); + if (!x2.equals(crt)) { + out.println("*** Certificate mismatch ***"); + testResult = false; + } + + X509Certificate x3 = generateCertificate(V3_B64_FILE); + if (!x3.equals(crt)) { + out.println("*** Certificate mismatch ***"); + testResult = false; + } + + return testResult; + } + + static X509Certificate generateCertificate(String certFile) { + try (InputStream inStrm = new FileInputStream(certFile)) { + CertificateFactory cf = CertificateFactory.getInstance("X509"); + X509Certificate x2 + = (X509Certificate) cf.generateCertificate(inStrm); + return x2; + } catch (CertificateException | IOException e) { + throw new RuntimeException("Exception while " + + "genrating certificate for " + certFile, e); + } + } +}