diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk index e8a2223f67a53e64f6f21a5fdc2fec1dc84639ba..2ad599cbe235749e97c5128835fc249191bce42c 100644 --- a/make/java/java/FILES_java.gmk +++ b/make/java/java/FILES_java.gmk @@ -454,6 +454,8 @@ JAVA_JAVA_java = \ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ sun/misc/JavaIOFileDescriptorAccess.java \ - sun/misc/JavaNioAccess.java + sun/misc/JavaNioAccess.java \ + sun/misc/Perf.java \ + sun/misc/PerfCounter.java FILES_java = $(JAVA_JAVA_java) diff --git a/make/sun/security/Makefile b/make/sun/security/Makefile index 2b7cc6b2ab342719694df42a2015780f5c07fad8..92371cc60cbf5681f4434dbcb355ac8cafcc7117 100644 --- a/make/sun/security/Makefile +++ b/make/sun/security/Makefile @@ -60,8 +60,15 @@ ifeq ($(PLATFORM), windows) endif endif -SUBDIRS = ec other action util tools jgss krb5 smartcardio $(PKCS11) \ - $(JGSS_WRAPPER) $(MSCAPI) +# Build in-tree elliptic curve crypto provider only when +# DISABLE_INTREE_EC is not set +INTREE_EC = ec +ifdef DISABLE_INTREE_EC + INTREE_EC = +endif + +SUBDIRS = $(INTREE_EC) other action util tools jgss krb5 smartcardio \ + $(PKCS11) $(JGSS_WRAPPER) $(MSCAPI) all build clean clobber:: $(SUBDIRS-loop) diff --git a/src/share/bin/java.h b/src/share/bin/java.h index fe039cdcc88452d2562c88e475e3478309432f79..cebdb5fc81afad84d0c6415886636434d03ab0f6 100644 --- a/src/share/bin/java.h +++ b/src/share/bin/java.h @@ -187,9 +187,6 @@ void InitLauncher(jboolean javaw); * */ typedef jclass (JNICALL FindClassFromBootLoader_t(JNIEnv *env, - const char *name, - jboolean init, - jobject loader, - jboolean throwError)); + const char *name)); jclass FindBootStrapClass(JNIEnv *env, const char *classname); #endif /* _JAVA_H_ */ diff --git a/src/share/bin/parse_manifest.c b/src/share/bin/parse_manifest.c index 6dcca091a4bb3c6be3324cda7217ad54f00342fc..a59540213c2dc4ce20585b000b725cbe5cff25c7 100644 --- a/src/share/bin/parse_manifest.c +++ b/src/share/bin/parse_manifest.c @@ -59,7 +59,7 @@ inflate_file(int fd, zentry *entry, int *size_out) char *out; z_stream zs; - if (entry->csize == 0xffffffff || entry->isize == 0xffffffff) + if (entry->csize == (size_t) -1 || entry->isize == (size_t) -1 ) return (NULL); if (lseek(fd, entry->offset, SEEK_SET) < (off_t)0) return (NULL); diff --git a/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java b/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java index 002d20785ff45dcc52fff642db6f4e5406d6f0da..1ebeb565ddbc651bb48351df81ec105bd060c799 100644 --- a/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java +++ b/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java @@ -133,7 +133,7 @@ public class JdbcRowSetResourceBundle implements Serializable { * This method returns an enumerated handle of the keys * which correspond to values translated to various locales. * - * @returns an enumerated keys which have messages tranlated to + * @return an enumeration of keys which have messages tranlated to * corresponding locales. */ public Enumeration getKeys() { @@ -146,7 +146,7 @@ public class JdbcRowSetResourceBundle implements Serializable { * returns the corresponding value reading it * from the Resource Bundle loaded earlier. * - * @returns value in locale specific language + * @return value in locale specific language * according to the key passed. */ public Object handleGetObject(String key) { diff --git a/src/share/classes/com/sun/rowset/JoinRowSetImpl.java b/src/share/classes/com/sun/rowset/JoinRowSetImpl.java index 7908848b2974be904947a15f01fc3c05ccc29f7d..d301c605cdb829526a5c902d1e12c374467a5530 100644 --- a/src/share/classes/com/sun/rowset/JoinRowSetImpl.java +++ b/src/share/classes/com/sun/rowset/JoinRowSetImpl.java @@ -3737,7 +3737,6 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { * Returns a result set containing the original value of the current * row only. * - * @return the original result set of the row * @throws SQLException if there is no current row * @see #setOriginalRow */ diff --git a/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java b/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java index 8db17537187b108c21780b6d9db789a500f6ed51..f25cec7e62e0fae47927ac9c3686e17745b885d7 100644 --- a/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java +++ b/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java @@ -46,6 +46,17 @@ import javax.sql.rowset.spi.*; */ public class WebRowSetXmlReader implements XmlReader, Serializable { + + private JdbcRowSetResourceBundle resBundle; + + public WebRowSetXmlReader(){ + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + } + /** * Parses the given WebRowSet object, getting its input from * the given java.io.Reader object. The parser will send @@ -69,17 +80,6 @@ public class WebRowSetXmlReader implements XmlReader, Serializable { * reader for the given rowset * @see XmlReaderContentHandler */ - - private JdbcRowSetResourceBundle resBundle; - - public WebRowSetXmlReader(){ - try { - resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); - } catch(IOException ioe) { - throw new RuntimeException(ioe); - } - } - public void readXML(WebRowSet caller, java.io.Reader reader) throws SQLException { try { // Crimson Parser(as in J2SE 1.4.1 is NOT able to handle diff --git a/src/share/classes/java/lang/Class.java b/src/share/classes/java/lang/Class.java index ddf5763179019e8e521c68bb76252f55a3328730..46414ad849164d034cbebf9d8de9a8cc64bbd090 100644 --- a/src/share/classes/java/lang/Class.java +++ b/src/share/classes/java/lang/Class.java @@ -565,8 +565,9 @@ public final * represented by this object. */ public String getName() { + String name = this.name; if (name == null) - name = getName0(); + this.name = name = getName0(); return name; } diff --git a/src/share/classes/java/lang/ClassLoader.java b/src/share/classes/java/lang/ClassLoader.java index d25100958a00980f9ba4b9ed95b73df115030e4c..9fec9b570a06ad2eb10b09ab62a4c4888e677267 100644 --- a/src/share/classes/java/lang/ClassLoader.java +++ b/src/share/classes/java/lang/ClassLoader.java @@ -380,16 +380,28 @@ public abstract class ClassLoader { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { + long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { - c = findBootstrapClass0(name); + c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { + // ClassNotFoundException thrown if class not found + // from the non-null parent class loader + } + + if (c == null) { // If still not found, then invoke findClass in order // to find the class. + long t1 = System.nanoTime(); c = findClass(name); + + // this is the defining class loader; record the stats + sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); + sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); + sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { @@ -1008,22 +1020,29 @@ public abstract class ClassLoader { if (system == null) { if (!checkName(name)) throw new ClassNotFoundException(name); - return findBootstrapClass(name); + Class cls = findBootstrapClass(name); + if (cls == null) { + throw new ClassNotFoundException(name); + } + return cls; } return system.loadClass(name); } - private Class findBootstrapClass0(String name) - throws ClassNotFoundException + /** + * Returns a class loaded by the bootstrap class loader; + * or return null if not found. + */ + private Class findBootstrapClassOrNull(String name) { check(); - if (!checkName(name)) - throw new ClassNotFoundException(name); + if (!checkName(name)) return null; + return findBootstrapClass(name); } - private native Class findBootstrapClass(String name) - throws ClassNotFoundException; + // return null if not found + private native Class findBootstrapClass(String name); // Check to make sure the class loader has been initialized. private void check() { diff --git a/src/share/classes/java/net/URLClassLoader.java b/src/share/classes/java/net/URLClassLoader.java index 22be20b7ecd5fc43cfcc377d0060dc2a13edf661..c4f775db71a18703a81e4f0d6ec482a727bd95e2 100644 --- a/src/share/classes/java/net/URLClassLoader.java +++ b/src/share/classes/java/net/URLClassLoader.java @@ -340,6 +340,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * used. */ private Class defineClass(String name, Resource res) throws IOException { + long t0 = System.nanoTime(); int i = name.lastIndexOf('.'); URL url = res.getCodeSourceURL(); if (i != -1) { @@ -370,12 +371,14 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { // Use (direct) ByteBuffer: CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); + sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); return defineClass(name, bb, cs); } else { byte[] b = res.getBytes(); // must read certificates AFTER reading bytes. CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); + sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); return defineClass(name, b, 0, b.length, cs); } } diff --git a/src/share/classes/java/net/doc-files/net-properties.html b/src/share/classes/java/net/doc-files/net-properties.html index e6b6330ba42aa3e00ae63ca478b1ca523fc809e6..384abd8d93fce0b9a3f1f53f33574c78d0c6706d 100644 --- a/src/share/classes/java/net/doc-files/net-properties.html +++ b/src/share/classes/java/net/doc-files/net-properties.html @@ -71,12 +71,12 @@ of proxies.

  • HTTP

    The following proxy settings are used by the HTTP protocol handler.

    +

    The default value excludes all common variations of the loopback address.

    +
  • HTTPS
    This is HTTP over SSL, a secure version of HTTP mainly used when confidentiality (like on payment sites) is needed.

    The following proxy settings are used by the HTTPS protocol handler.

    @@ -107,7 +108,7 @@ of proxies.

  • ftp.proxyPort (default: 80)
    The port number of the proxy server.

    -
  • ftp.nonProxyHosts (default: <none>)
    +

  • ftp.nonProxyHosts (default: localhost|127.*|[::1])
    Indicates the hosts that should be accessed without going through the proxy. Typically this defines internal hosts. The value of this property is a list of hosts, separated by @@ -117,6 +118,7 @@ of proxies.

    will indicate that every hosts in the foo.com domain and the localhost should be accessed directly even if a proxy server is specified.

    +

    The default value excludes all common variations of the loopback address.

  • SOCKS
    This is another type of proxy. It allows for lower level type of tunneling since it works at the TCP level. In effect, diff --git a/src/share/classes/java/nio/file/FileTreeWalker.java b/src/share/classes/java/nio/file/FileTreeWalker.java index 71cb86eb88a883606900dbb906b9f62086626694..1452bd66b2aa96dc2ad4ba190d947849493e17cf 100644 --- a/src/share/classes/java/nio/file/FileTreeWalker.java +++ b/src/share/classes/java/nio/file/FileTreeWalker.java @@ -41,8 +41,12 @@ class FileTreeWalker { private final boolean detectCycles; private final LinkOption[] linkOptions; private final FileVisitor visitor; + private final int maxDepth; - FileTreeWalker(Set options, FileVisitor visitor) { + FileTreeWalker(Set options, + FileVisitor visitor, + int maxDepth) + { boolean fl = false; boolean dc = false; for (FileVisitOption option: options) { @@ -58,18 +62,15 @@ class FileTreeWalker { this.linkOptions = (fl) ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; this.visitor = visitor; + this.maxDepth = maxDepth; } /** * Walk file tree starting at the given file */ - void walk(Path start, int maxDepth) { - // don't use attributes of starting file as they may be stale - if (start instanceof BasicFileAttributesHolder) { - ((BasicFileAttributesHolder)start).invalidate(); - } + void walk(Path start) { FileVisitResult result = walk(start, - maxDepth, + 0, new ArrayList()); if (result == null) { throw new NullPointerException("Visitor returned 'null'"); @@ -89,12 +90,15 @@ class FileTreeWalker { List ancestors) { // depth check - if (depth-- < 0) + if (depth > maxDepth) return FileVisitResult.CONTINUE; // if attributes are cached then use them if possible BasicFileAttributes attrs = null; - if (file instanceof BasicFileAttributesHolder) { + if ((depth > 0) && + (file instanceof BasicFileAttributesHolder) && + (System.getSecurityManager() == null)) + { BasicFileAttributes cached = ((BasicFileAttributesHolder)file).get(); if (!followLinks || !cached.isSymbolicLink()) attrs = cached; @@ -120,6 +124,10 @@ class FileTreeWalker { } } } catch (SecurityException x) { + // If access to starting file is denied then SecurityException + // is thrown, otherwise the file is ignored. + if (depth == 0) + throw x; return FileVisitResult.CONTINUE; } } @@ -196,7 +204,7 @@ class FileTreeWalker { try { for (Path entry: stream) { inAction = true; - result = walk(entry, depth, ancestors); + result = walk(entry, depth+1, ancestors); inAction = false; // returning null will cause NPE to be thrown diff --git a/src/share/classes/java/nio/file/Files.java b/src/share/classes/java/nio/file/Files.java index bf596409e5a5724364e342b9fb35331e262268a7..ca5bc5698e1db19ea601a3cd6bc6f4ca48c4bdfa 100644 --- a/src/share/classes/java/nio/file/Files.java +++ b/src/share/classes/java/nio/file/Files.java @@ -223,7 +223,7 @@ public final class Files { { if (maxDepth < 0) throw new IllegalArgumentException("'maxDepth' is negative"); - new FileTreeWalker(options, visitor).walk(start, maxDepth); + new FileTreeWalker(options, visitor, maxDepth).walk(start); } /** diff --git a/src/share/classes/java/util/logging/ErrorManager.java b/src/share/classes/java/util/logging/ErrorManager.java index 39c215151fc2180de3033f000c45c88884293d9c..8a6d935dea3456f626297738a464236a10a49faf 100644 --- a/src/share/classes/java/util/logging/ErrorManager.java +++ b/src/share/classes/java/util/logging/ErrorManager.java @@ -28,7 +28,7 @@ package java.util.logging; /** * ErrorManager objects can be attached to Handlers to process - * any error that occur on a Handler during Logging. + * any error that occurs on a Handler during Logging. *

    * When processing logging output, if a Handler encounters problems * then rather than throwing an Exception back to the issuer of @@ -72,7 +72,7 @@ public class ErrorManager { /** * The error method is called when a Handler failure occurs. *

    - * This method may be overriden in subclasses. The default + * This method may be overridden in subclasses. The default * behavior in this base class is that the first call is * reported to System.err, and subsequent calls are ignored. * diff --git a/src/share/classes/java/util/logging/FileHandler.java b/src/share/classes/java/util/logging/FileHandler.java index a4f18bd2130c8705c21d27204a4253980912f396..23031a010c8bf8b5b8d43a341d51900bf08730da 100644 --- a/src/share/classes/java/util/logging/FileHandler.java +++ b/src/share/classes/java/util/logging/FileHandler.java @@ -39,7 +39,7 @@ import java.security.*; * For a rotating set of files, as each file reaches a given size * limit, it is closed, rotated out, and a new file opened. * Successively older files are named by adding "0", "1", "2", - * etc into the base filename. + * etc. into the base filename. *

    * By default buffering is enabled in the IO libraries but each log * record is flushed out when it is complete. @@ -391,7 +391,7 @@ public class FileHandler extends StreamHandler { // Generate a lock file name from the "unique" int. lockFileName = generate(pattern, 0, unique).toString() + ".lck"; // Now try to lock that filename. - // Because some systems (e.g. Solaris) can only do file locks + // Because some systems (e.g., Solaris) can only do file locks // between processes (and not within a process), we first check // if we ourself already have the file locked. synchronized(locks) { diff --git a/src/share/classes/java/util/logging/Formatter.java b/src/share/classes/java/util/logging/Formatter.java index 7e7030ba6b0bef63a0bde0c8914dd8aac5db96d9..7cf5c1764a1b3500b247e12a4d0a74796753d786 100644 --- a/src/share/classes/java/util/logging/Formatter.java +++ b/src/share/classes/java/util/logging/Formatter.java @@ -52,7 +52,7 @@ public abstract class Formatter { * Format the given log record and return the formatted string. *

    * The resulting formatted String will normally include a - * localized and formated version of the LogRecord's message field. + * localized and formatted version of the LogRecord's message field. * It is recommended to use the {@link Formatter#formatMessage} * convenience method to localize and format the message field. * @@ -66,7 +66,7 @@ public abstract class Formatter { * Return the header string for a set of formatted records. *

    * This base class returns an empty string, but this may be - * overriden by subclasses. + * overridden by subclasses. * * @param h The target handler (can be null) * @return header string @@ -79,7 +79,7 @@ public abstract class Formatter { * Return the tail string for a set of formatted records. *

    * This base class returns an empty string, but this may be - * overriden by subclasses. + * overridden by subclasses. * * @param h The target handler (can be null) * @return tail string diff --git a/src/share/classes/java/util/logging/Handler.java b/src/share/classes/java/util/logging/Handler.java index 2643c73471489332498d7f15a0b3aeaf5719071d..7c1c6268b00bc795eaf796d918494b207ddfb3c0 100644 --- a/src/share/classes/java/util/logging/Handler.java +++ b/src/share/classes/java/util/logging/Handler.java @@ -274,7 +274,7 @@ public abstract class Handler { * Level and whether it satisfies any Filter. It also * may make other Handler specific checks that might prevent a * handler from logging the LogRecord. It will return false if - * the LogRecord is Null. + * the LogRecord is null. *

    * @param record a LogRecord * @return true if the LogRecord would be logged. diff --git a/src/share/classes/java/util/logging/Level.java b/src/share/classes/java/util/logging/Level.java index 910a50d1ebba75aee5f7725cfb5ee1ef465cf080..173201f80eee201a02e4fdb10745ae6271d0f0a2 100644 --- a/src/share/classes/java/util/logging/Level.java +++ b/src/share/classes/java/util/logging/Level.java @@ -110,7 +110,7 @@ public class Level implements java.io.Serializable { * Typically INFO messages will be written to the console * or its equivalent. So the INFO level should only be * used for reasonably significant messages that will - * make sense to end users and system admins. + * make sense to end users and system administrators. * This level is initialized to 800. */ public static final Level INFO = new Level("INFO", 800, defaultBundle); @@ -245,6 +245,8 @@ public class Level implements java.io.Serializable { } /** + * Returns a string representation of this Level. + * * @return the non-localized name of the Level, for example "INFO". */ public final String toString() { @@ -299,14 +301,14 @@ public class Level implements java.io.Serializable { * @throws IllegalArgumentException if the value is not valid. * Valid values are integers between Integer.MIN_VALUE * and Integer.MAX_VALUE, and all known level names. - * Known names are the levels defined by this class (i.e. FINE, + * Known names are the levels defined by this class (e.g., FINE, * FINER, FINEST), or created by this class with * appropriate package access, or new levels defined or created * by subclasses. * * @return The parsed value. Passing an integer that corresponds to a known name - * (eg 700) will return the associated name (eg CONFIG). - * Passing an integer that does not (eg 1) will return a new level name + * (e.g., 700) will return the associated name (e.g., CONFIG). + * Passing an integer that does not (e.g., 1) will return a new level name * initialized to that value. */ public static synchronized Level parse(String name) throws IllegalArgumentException { diff --git a/src/share/classes/java/util/logging/LogRecord.java b/src/share/classes/java/util/logging/LogRecord.java index 2610316a5e38b7e1a08d2d5c11dd90f7c63d84b7..6e659ba4ea783827cce14f4ffd452bba7667f88c 100644 --- a/src/share/classes/java/util/logging/LogRecord.java +++ b/src/share/classes/java/util/logging/LogRecord.java @@ -188,7 +188,7 @@ public class LogRecord implements java.io.Serializable { } /** - * Get the source Logger name's + * Get the source Logger's name. * * @return source logger name (may be null) */ @@ -197,7 +197,7 @@ public class LogRecord implements java.io.Serializable { } /** - * Set the source Logger name. + * Set the source Logger's name. * * @param name the source logger name (may be null) */ diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java index 5ae2b42713361f38875dd8141a1c172ebb1861e4..cd9f4d90568cbc7371762e1a206d4eb8daf1eea7 100644 --- a/src/share/classes/java/util/logging/Logger.java +++ b/src/share/classes/java/util/logging/Logger.java @@ -66,7 +66,7 @@ import java.lang.ref.WeakReference; * effective level from its parent. *

    * On each logging call the Logger initially performs a cheap - * check of the request level (e.g. SEVERE or FINE) against the + * check of the request level (e.g., SEVERE or FINE) against the * effective log level of the logger. If the request level is * lower than the log level, the logging call returns immediately. *

    @@ -230,7 +230,7 @@ public class Logger { * Protected method to construct a logger for a named subsystem. *

    * The logger will be initially configured with a null Level - * and with useParentHandlers true. + * and with useParentHandlers set to true. * * @param name A name for the logger. This should * be a dot-separated name and should normally @@ -240,7 +240,7 @@ public class Logger { * @param resourceBundleName name of ResourceBundle to be used for localizing * messages for this logger. May be null if none * of the messages require localization. - * @throws MissingResourceException if the ResourceBundleName is non-null and + * @throws MissingResourceException if the resourceBundleName is non-null and * no corresponding resource can be found. */ protected Logger(String name, String resourceBundleName) { @@ -285,7 +285,7 @@ public class Logger { *

    * If a new logger is created its log level will be configured * based on the LogManager configuration and it will configured - * to also send logging output to its parent's handlers. It will + * to also send logging output to its parent's Handlers. It will * be registered in the LogManager global namespace. * * @param name A name for the logger. This should @@ -308,7 +308,7 @@ public class Logger { *

    * If a new logger is created its log level will be configured * based on the LogManager and it will configured to also send logging - * output to its parent loggers Handlers. It will be registered in + * output to its parent's Handlers. It will be registered in * the LogManager global namespace. *

    * If the named Logger already exists and does not yet have a @@ -326,7 +326,8 @@ public class Logger { * messages for this logger. May be null if none of * the messages require localization. * @return a suitable Logger - * @throws MissingResourceException if the named ResourceBundle cannot be found. + * @throws MissingResourceException if the resourceBundleName is non-null and + * no corresponding resource can be found. * @throws IllegalArgumentException if the Logger already exists and uses * a different resource bundle name. * @throws NullPointerException if the name is null. @@ -395,7 +396,8 @@ public class Logger { * messages for this logger. * May be null if none of the messages require localization. * @return a newly created private Logger - * @throws MissingResourceException if the named ResourceBundle cannot be found. + * @throws MissingResourceException if the resourceBundleName is non-null and + * no corresponding resource can be found. */ public static synchronized Logger getAnonymousLogger(String resourceBundleName) { LogManager manager = LogManager.getLogManager(); @@ -514,7 +516,7 @@ public class Logger { * level then the given message is forwarded to all the * registered output Handler objects. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param msg The string message (or a key in the message catalog) */ public void log(Level level, String msg) { @@ -532,7 +534,7 @@ public class Logger { * level then a corresponding LogRecord is created and forwarded * to all the registered output Handler objects. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param msg The string message (or a key in the message catalog) * @param param1 parameter to the message */ @@ -553,7 +555,7 @@ public class Logger { * level then a corresponding LogRecord is created and forwarded * to all the registered output Handler objects. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param msg The string message (or a key in the message catalog) * @param params array of parameters to the message */ @@ -578,7 +580,7 @@ public class Logger { * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param msg The string message (or a key in the message catalog) * @param thrown Throwable associated with log message. */ @@ -603,7 +605,7 @@ public class Logger { * level then the given message is forwarded to all the * registered output Handler objects. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param msg The string message (or a key in the message catalog) @@ -626,7 +628,7 @@ public class Logger { * level then a corresponding LogRecord is created and forwarded * to all the registered output Handler objects. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param msg The string message (or a key in the message catalog) @@ -653,7 +655,7 @@ public class Logger { * level then a corresponding LogRecord is created and forwarded * to all the registered output Handler objects. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param msg The string message (or a key in the message catalog) @@ -684,7 +686,7 @@ public class Logger { * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param msg The string message (or a key in the message catalog) @@ -731,7 +733,7 @@ public class Logger { * resource bundle name is null, or an empty String or invalid * then the msg string is not localized. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param bundleName name of resource bundle to localize msg, @@ -762,7 +764,7 @@ public class Logger { * resource bundle name is null, or an empty String or invalid * then the msg string is not localized. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param bundleName name of resource bundle to localize msg, @@ -795,7 +797,7 @@ public class Logger { * resource bundle name is null, or an empty String or invalid * then the msg string is not localized. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param bundleName name of resource bundle to localize msg, @@ -832,7 +834,7 @@ public class Logger { * processed specially by output Formatters and is not treated * as a formatting parameter to the LogRecord message property. *

    - * @param level One of the message level identifiers, e.g. SEVERE + * @param level One of the message level identifiers, e.g., SEVERE * @param sourceClass name of class that issued the logging request * @param sourceMethod name of method that issued the logging request * @param bundleName name of resource bundle to localize msg, @@ -1214,7 +1216,7 @@ public class Logger { /** * Specify whether or not this logger should send its output - * to it's parent Logger. This means that any LogRecords will + * to its parent Logger. This means that any LogRecords will * also be written to the parent's Handlers, and potentially * to its parent, recursively up the namespace. * diff --git a/src/share/classes/java/util/logging/LoggingMXBean.java b/src/share/classes/java/util/logging/LoggingMXBean.java index cb67d7b4fb071c410615b21956750df0c50a5d6e..a3abe3c69b16fc4cc0c848c1ca5940e9625b0fa8 100644 --- a/src/share/classes/java/util/logging/LoggingMXBean.java +++ b/src/share/classes/java/util/logging/LoggingMXBean.java @@ -105,8 +105,8 @@ public interface LoggingMXBean extends PlatformManagedObject { * * @param loggerName The name of the Logger to be set. * Must be non-null. - * @param levelName The name of the level to set the specified logger to, - * or null if to set the level to inherit + * @param levelName The name of the level to set on the specified logger, + * or null if setting the level to inherit * from its nearest ancestor. * * @throws IllegalArgumentException if the specified logger diff --git a/src/share/classes/java/util/logging/MemoryHandler.java b/src/share/classes/java/util/logging/MemoryHandler.java index d812e3bf64f82cdb02afd4e94b5d53ee3c8fc9f2..aa632223667fd0b8e10ab36e252dd830883b391e 100644 --- a/src/share/classes/java/util/logging/MemoryHandler.java +++ b/src/share/classes/java/util/logging/MemoryHandler.java @@ -136,7 +136,7 @@ public class MemoryHandler extends Handler { * @param size the number of log records to buffer (must be greater than zero) * @param pushLevel message level to push on * - * @throws IllegalArgumentException is size is <= 0 + * @throws IllegalArgumentException if size is <= 0 */ public MemoryHandler(Handler target, int size, Level pushLevel) { if (target == null || pushLevel == null) { @@ -258,7 +258,7 @@ public class MemoryHandler extends Handler { * This method checks if the LogRecord has an appropriate level and * whether it satisfies any Filter. However it does not * check whether the LogRecord would result in a "push" of the - * buffer contents. It will return false if the LogRecord is Null. + * buffer contents. It will return false if the LogRecord is null. *

    * @param record a LogRecord * @return true if the LogRecord would be logged. diff --git a/src/share/classes/java/util/logging/StreamHandler.java b/src/share/classes/java/util/logging/StreamHandler.java index 766142a1a58883c1ae758bcd998cfbe6e9b241ab..ce47fe904272f39e6778cefc72a9f9ef4717d6bd 100644 --- a/src/share/classes/java/util/logging/StreamHandler.java +++ b/src/share/classes/java/util/logging/StreamHandler.java @@ -220,7 +220,7 @@ public class StreamHandler extends Handler { *

    * This method checks if the LogRecord has an appropriate level and * whether it satisfies any Filter. It will also return false if - * no output stream has been assigned yet or the LogRecord is Null. + * no output stream has been assigned yet or the LogRecord is null. *

    * @param record a LogRecord * @return true if the LogRecord would be logged. diff --git a/src/share/classes/java/util/zip/ZipEntry.java b/src/share/classes/java/util/zip/ZipEntry.java index cba69b0c1a2e37cbdc15562fbf2b8f78c469be77..0e2ddaec3fb15abaf09987e5ee8fa4c88e1fed25 100644 --- a/src/share/classes/java/util/zip/ZipEntry.java +++ b/src/share/classes/java/util/zip/ZipEntry.java @@ -253,14 +253,10 @@ class ZipEntry implements ZipConstants, Cloneable { * the first 0xFFFF bytes are output to the ZIP file entry. * * @param comment the comment string - * @exception IllegalArgumentException if the length of the specified - * comment string is greater than 0xFFFF bytes + * * @see #getComment() */ public void setComment(String comment) { - if (comment != null && comment.length() > 0xffff) { - throw new IllegalArgumentException("invalid entry comment length"); - } this.comment = comment; } diff --git a/src/share/classes/java/util/zip/ZipFile.java b/src/share/classes/java/util/zip/ZipFile.java index 76c270c1b1019561548c503dbf65ecd1323206a6..583d7dcfe1aa7d250eecf439a51fb258eec1f503 100644 --- a/src/share/classes/java/util/zip/ZipFile.java +++ b/src/share/classes/java/util/zip/ZipFile.java @@ -195,7 +195,10 @@ class ZipFile implements ZipConstants, Closeable { if (charset == null) throw new NullPointerException("charset is null"); this.zc = ZipCoder.get(charset); + long t0 = System.nanoTime(); jzfile = open(name, mode, file.lastModified()); + sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); + sun.misc.PerfCounter.getZipFileCount().increment(); this.name = name; this.total = getTotal(jzfile); } diff --git a/src/share/classes/javax/sql/rowset/BaseRowSet.java b/src/share/classes/javax/sql/rowset/BaseRowSet.java index 2d13d835c1ba3989f727b71422aa23fc4e8d96d9..f3e79555ba1d80d3890ccf398ef0ba6f692d1afc 100644 --- a/src/share/classes/javax/sql/rowset/BaseRowSet.java +++ b/src/share/classes/javax/sql/rowset/BaseRowSet.java @@ -168,8 +168,8 @@ import javax.sql.rowset.serial.*; * The majority of methods for setting placeholder parameters take two parameters, * with the first parameter * indicating which placeholder parameter is to be set, and the second parameter - * giving the value to be set. Methods such as getInt, - * getString, getBoolean, and getLong fall into + * giving the value to be set. Methods such as setInt, + * setString, setBoolean, and setLong fall into * this category. After these methods have been called, a call to the method * getParams will return an array with the values that have been set. Each * element in the array is an Object instance representing the @@ -3259,9 +3259,9 @@ public static final int ASCII_STREAM_PARAM = 2; * @param x the parameter value * @exception SQLException if a database access error occurs or * this method is called on a closed CallableStatement - * @see #getBoolean * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method + * @see #getParams * @since 1.4 */ public void setBoolean(String parameterName, boolean x) throws SQLException{ @@ -3281,7 +3281,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getByte + * @see #getParams * @since 1.4 */ public void setByte(String parameterName, byte x) throws SQLException{ @@ -3301,7 +3301,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getShort + * @see #getParams * @since 1.4 */ public void setShort(String parameterName, short x) throws SQLException{ @@ -3320,7 +3320,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getInt + * @see #getParams * @since 1.4 */ public void setInt(String parameterName, int x) throws SQLException{ @@ -3339,7 +3339,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getLong + * @see #getParams * @since 1.4 */ public void setLong(String parameterName, long x) throws SQLException{ @@ -3358,7 +3358,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getFloat + * @see #getParams * @since 1.4 */ public void setFloat(String parameterName, float x) throws SQLException{ @@ -3377,7 +3377,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getDouble + * @see #getParams * @since 1.4 */ public void setDouble(String parameterName, double x) throws SQLException{ @@ -3398,7 +3398,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getBigDecimal + * @see #getParams * @since 1.4 */ public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException{ @@ -3421,7 +3421,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getString + * @see #getParams * @since 1.4 */ public void setString(String parameterName, String x) throws SQLException{ @@ -3443,7 +3443,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getBytes + * @see #getParams * @since 1.4 */ public void setBytes(String parameterName, byte x[]) throws SQLException{ @@ -3464,7 +3464,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getTimestamp + * @see #getParams * @since 1.4 */ public void setTimestamp(String parameterName, java.sql.Timestamp x) @@ -3712,7 +3712,7 @@ public static final int ASCII_STREAM_PARAM = 2; * or STRUCT data type and the JDBC driver does not support * this data type * @see Types - * @see #getObject + * @see #getParams * @since 1.4 */ public void setObject(String parameterName, Object x, int targetSqlType, int scale) @@ -3740,7 +3740,7 @@ public static final int ASCII_STREAM_PARAM = 2; * REF, ROWID, SQLXML * or STRUCT data type and the JDBC driver does not support * this data type - * @see #getObject + * @see #getParams * @since 1.4 */ public void setObject(String parameterName, Object x, int targetSqlType) @@ -3782,7 +3782,7 @@ public static final int ASCII_STREAM_PARAM = 2; * Object parameter is ambiguous * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getObject + * @see #getParams * @since 1.4 */ public void setObject(String parameterName, Object x) throws SQLException{ @@ -4064,7 +4064,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getDate + * @see #getParams * @since 1.4 */ public void setDate(String parameterName, java.sql.Date x) @@ -4091,7 +4091,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getDate + * @see #getParams * @since 1.4 */ public void setDate(String parameterName, java.sql.Date x, Calendar cal) @@ -4111,7 +4111,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getTime + * @see #getParams * @since 1.4 */ public void setTime(String parameterName, java.sql.Time x) @@ -4138,7 +4138,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getTime + * @see #getParams * @since 1.4 */ public void setTime(String parameterName, java.sql.Time x, Calendar cal) @@ -4165,7 +4165,7 @@ public static final int ASCII_STREAM_PARAM = 2; * this method is called on a closed CallableStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @see #getTimestamp + * @see #getParams * @since 1.4 */ public void setTimestamp(String parameterName, java.sql.Timestamp x, Calendar cal) diff --git a/src/share/classes/sun/misc/PerfCounter.java b/src/share/classes/sun/misc/PerfCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..8c47234407a4cc2f81066521e2a455d024784904 --- /dev/null +++ b/src/share/classes/sun/misc/PerfCounter.java @@ -0,0 +1,191 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.misc; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.LongBuffer; +import java.security.AccessController; + +/** + * Performance counter support for internal JRE classes. + * This class defines a fixed list of counters for the platform + * to use as an interim solution until RFE# 6209222 is implemented. + * The perf counters will be created in the jvmstat perf buffer + * that the HotSpot VM creates. The default size is 32K and thus + * the number of counters is bounded. You can alter the size + * with -XX:PerfDataMemorySize= option. If there is + * insufficient memory in the jvmstat perf buffer, the C heap memory + * will be used and thus the application will continue to run if + * the counters added exceeds the buffer size but the counters + * will be missing. + * + * See HotSpot jvmstat implementation for certain circumstances + * that the jvmstat perf buffer is not supported. + * + */ +public class PerfCounter { + private static final Perf perf = + AccessController.doPrivileged(new Perf.GetPerfAction()); + + // Must match values defined in hotspot/src/share/vm/runtime/perfdata.hpp + private final static int V_Constant = 1; + private final static int V_Monotonic = 2; + private final static int V_Variable = 3; + private final static int U_None = 1; + + private final String name; + private final LongBuffer lb; + + private PerfCounter(String name, int type) { + this.name = name; + ByteBuffer bb = perf.createLong(name, U_None, type, 0L); + bb.order(ByteOrder.nativeOrder()); + this.lb = bb.asLongBuffer(); + } + + static PerfCounter newPerfCounter(String name) { + return new PerfCounter(name, V_Variable); + } + + static PerfCounter newConstantPerfCounter(String name) { + PerfCounter c = new PerfCounter(name, V_Constant); + return c; + } + + /** + * Returns the current value of the perf counter. + */ + public synchronized long get() { + return lb.get(0); + } + + /** + * Sets the value of the perf counter to the given newValue. + */ + public synchronized void set(long newValue) { + lb.put(0, newValue); + } + + /** + * Adds the given value to the perf counter. + */ + public synchronized void add(long value) { + long res = get() + value; + lb.put(0, res); + } + + /** + * Increments the perf counter with 1. + */ + public void increment() { + add(1); + } + + /** + * Adds the given interval to the perf counter. + */ + public void addTime(long interval) { + add(interval); + } + + /** + * Adds the elapsed time from the given start time (ns) to the perf counter. + */ + public void addElapsedTimeFrom(long startTime) { + add(System.nanoTime() - startTime); + } + + @Override + public String toString() { + return name + " = " + get(); + } + + static class CoreCounters { + static final PerfCounter pdt = newPerfCounter("sun.classloader.parentDelegationTime"); + static final PerfCounter lc = newPerfCounter("sun.classloader.findClasses"); + static final PerfCounter lct = newPerfCounter("sun.classloader.findClassTime"); + static final PerfCounter rcbt = newPerfCounter("sun.urlClassLoader.readClassBytesTime"); + static final PerfCounter zfc = newPerfCounter("sun.zip.zipFiles"); + static final PerfCounter zfot = newPerfCounter("sun.zip.zipFile.openTime"); + } + + static class WindowsClientCounters { + static final PerfCounter d3dAvailable = newConstantPerfCounter("sun.java2d.d3d.available"); + } + + /** + * Number of findClass calls + */ + public static PerfCounter getFindClasses() { + return CoreCounters.lc; + } + + /** + * Time (ns) spent in finding classes that includes + * lookup and read class bytes and defineClass + */ + public static PerfCounter getFindClassTime() { + return CoreCounters.lct; + } + + /** + * Time (ns) spent in finding classes + */ + public static PerfCounter getReadClassBytesTime() { + return CoreCounters.rcbt; + } + + /** + * Time (ns) spent in the parent delegation to + * the parent of the defining class loader + */ + public static PerfCounter getParentDelegationTime() { + return CoreCounters.pdt; + } + + /** + * Number of zip files opened. + */ + public static PerfCounter getZipFileCount() { + return CoreCounters.zfc; + } + + /** + * Time (ns) spent in opening the zip files that + * includes building the entries hash table + */ + public static PerfCounter getZipFileOpenTime() { + return CoreCounters.zfot; + } + + /** + * D3D graphic pipeline available + */ + public static PerfCounter getD3DAvailable() { + return WindowsClientCounters.d3dAvailable; + } +} diff --git a/src/share/classes/sun/net/spi/DefaultProxySelector.java b/src/share/classes/sun/net/spi/DefaultProxySelector.java index 714dc4ce5c3ba133a47825a1a13ab674ead65e63..af34ada8ccff61ccbc167044c8e16424d6afe727 100644 --- a/src/share/classes/sun/net/spi/DefaultProxySelector.java +++ b/src/share/classes/sun/net/spi/DefaultProxySelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 @@ -25,11 +25,9 @@ package sun.net.spi; -import sun.net.www.http.*; import sun.net.NetProperties; import java.net.*; import java.util.*; -import java.util.regex.*; import java.io.*; import sun.misc.RegexpPool; import java.security.AccessController; @@ -102,17 +100,22 @@ public class DefaultProxySelector extends ProxySelector { */ static class NonProxyInfo { + // Default value for nonProxyHosts, this provides backward compatibility + // by excluding localhost and its litteral notations. + static final String defStringVal = "localhost|127.*|[::1]"; + String hostsSource; RegexpPool hostsPool; - String property; - - static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null); - static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null); + final String property; + final String defaultVal; + static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null, defStringVal); + static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null, defStringVal); - NonProxyInfo(String p, String s, RegexpPool pool) { + NonProxyInfo(String p, String s, RegexpPool pool, String d) { property = p; hostsSource = s; hostsPool = pool; + defaultVal = d; } } @@ -130,7 +133,6 @@ public class DefaultProxySelector extends ProxySelector { } String protocol = uri.getScheme(); String host = uri.getHost(); - int port = uri.getPort(); if (host == null) { // This is a hack to ensure backward compatibility in two @@ -149,11 +151,6 @@ public class DefaultProxySelector extends ProxySelector { } i = auth.lastIndexOf(':'); if (i >= 0) { - try { - port = Integer.parseInt(auth.substring(i+1)); - } catch (NumberFormatException e) { - port = -1; - } auth = auth.substring(0,i); } host = auth; @@ -165,13 +162,6 @@ public class DefaultProxySelector extends ProxySelector { } List proxyl = new ArrayList(1); - // special case localhost and loopback addresses to - // not go through proxy - if (isLoopback(host)) { - proxyl.add(Proxy.NO_PROXY); - return proxyl; - } - NonProxyInfo pinfo = null; if ("http".equalsIgnoreCase(protocol)) { @@ -244,9 +234,14 @@ public class DefaultProxySelector extends ProxySelector { nphosts = NetProperties.get(nprop.property); synchronized (nprop) { if (nphosts == null) { - nprop.hostsSource = null; - nprop.hostsPool = null; - } else { + if (nprop.defaultVal != null) { + nphosts = nprop.defaultVal; + } else { + nprop.hostsSource = null; + nprop.hostsPool = null; + } + } + if (nphosts != null) { if (!nphosts.equals(nprop.hostsSource)) { RegexpPool pool = new RegexpPool(); StringTokenizer st = new StringTokenizer(nphosts, "|", false); @@ -334,107 +329,6 @@ public class DefaultProxySelector extends ProxySelector { } } - private boolean isLoopback(String host) { - if (host == null || host.length() == 0) - return false; - - if (host.equalsIgnoreCase("localhost")) - return true; - - /* The string could represent a numerical IP address. - * For IPv4 addresses, check whether it starts with 127. - * For IPv6 addresses, check whether it is ::1 or its equivalent. - * Don't check IPv4-mapped or IPv4-compatible addresses - */ - - if (host.startsWith("127.")) { - // possible IPv4 loopback address - int p = 4; - int q; - int n = host.length(); - // Per RFC2732: At most three digits per byte - // Further constraint: Each element fits in a byte - if ((q = scanByte(host, p, n)) <= p) return false; p = q; - if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0; p = q; - if ((q = scanByte(host, p, n)) <= p) return false; p = q; - if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0; p = q; - if ((q = scanByte(host, p, n)) <= p) return false; - return q == n && number > 0; - } - - if (host.endsWith(":1")) { - final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1"); - return p6.matcher(host).matches(); - } - return false; - } - - // Character-class masks, in reverse order from RFC2396 because - // initializers for static fields cannot make forward references. - - // Compute a low-order mask for the characters - // between first and last, inclusive - private static long lowMask(char first, char last) { - long m = 0; - int f = Math.max(Math.min(first, 63), 0); - int l = Math.max(Math.min(last, 63), 0); - for (int i = f; i <= l; i++) - m |= 1L << i; - return m; - } - // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | - // "8" | "9" - private static final long L_DIGIT = lowMask('0', '9'); - private static final long H_DIGIT = 0L; - - // Scan a string of decimal digits whose value fits in a byte - // - private int number; - private int scanByte(String input, int start, int n) - { - int p = start; - int q = scan(input, p, n, L_DIGIT, H_DIGIT); - if (q <= p) return q; - number = Integer.parseInt(input.substring(p, q)); - if (number > 255) return p; - return q; - } - - // Scan a specific char: If the char at the given start position is - // equal to c, return the index of the next char; otherwise, return the - // start position. - // - private int scan(String input, int start, int end, char c) { - if ((start < end) && (input.charAt(start) == c)) - return start + 1; - return start; - } - - // Scan chars that match the given mask pair - // - private int scan(String input, int start, int n, long lowMask, long highMask) - { - int p = start; - while (p < n) { - char c = input.charAt(p); - if (match(c, lowMask, highMask)) { - p++; - continue; - } - break; - } - return p; - } - - // Tell whether the given character is permitted by the given mask pair - private boolean match(char c, long lowMask, long highMask) { - if (c < 64) - return ((1L << c) & lowMask) != 0; - if (c < 128) - return ((1L << (c - 64)) & highMask) != 0; - return false; - } - private native static boolean init(); private native Proxy getSystemProxy(String protocol, String host); } diff --git a/src/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java b/src/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java new file mode 100644 index 0000000000000000000000000000000000000000..3310c93e4febaf43e44ca24f45dcacc129e9be18 --- /dev/null +++ b/src/share/classes/sun/security/action/GetBooleanSecurityPropertyAction.java @@ -0,0 +1,74 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.security.action; + +import java.security.Security; + +/** + * A convenience class for retrieving the boolean value of a security property + * as a privileged action. + * + *

    An instance of this class can be used as the argument of + * AccessController.doPrivileged. + * + *

    The following code retrieves the boolean value of the security + * property named "prop" as a privileged action:

    + * + *

    + * boolean b = java.security.AccessController.doPrivileged
    + *              (new GetBooleanSecurityPropertyAction("prop")).booleanValue();
    + * 
    + * + */ +public class GetBooleanSecurityPropertyAction + implements java.security.PrivilegedAction { + private String theProp; + + /** + * Constructor that takes the name of the security property whose boolean + * value needs to be determined. + * + * @param theProp the name of the security property + */ + public GetBooleanSecurityPropertyAction(String theProp) { + this.theProp = theProp; + } + + /** + * Determines the boolean value of the security property whose name was + * specified in the constructor. + * + * @return the Boolean value of the security property. + */ + public Boolean run() { + boolean b = false; + try { + String value = Security.getProperty(theProp); + b = (value != null) && value.equalsIgnoreCase("true"); + } catch (NullPointerException e) {} + return b; + } +} diff --git a/src/share/classes/sun/security/provider/certpath/Builder.java b/src/share/classes/sun/security/provider/certpath/Builder.java index 8e13fb8b777318f775cd0fdd9ce8e330adc1c7af..5892b1b328db20d953664ccd484d147133b11c32 100644 --- a/src/share/classes/sun/security/provider/certpath/Builder.java +++ b/src/share/classes/sun/security/provider/certpath/Builder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 @@ -26,12 +26,14 @@ package sun.security.provider.certpath; import java.io.IOException; +import java.security.AccessController; import java.security.GeneralSecurityException; import java.security.cert.*; import java.util.*; import javax.security.auth.x500.X500Principal; +import sun.security.action.GetBooleanAction; import sun.security.util.Debug; import sun.security.x509.GeneralNames; import sun.security.x509.GeneralNameInterface; @@ -64,9 +66,8 @@ public abstract class Builder { * Authority Information Access extension shall be enabled. Currently * disabled by default for compatibility reasons. */ - final static boolean USE_AIA = - DistributionPointFetcher.getBooleanProperty - ("com.sun.security.enableAIAcaIssuers", false); + final static boolean USE_AIA = AccessController.doPrivileged + (new GetBooleanAction("com.sun.security.enableAIAcaIssuers")); /** * Initialize the builder with the input parameters. diff --git a/src/share/classes/sun/security/provider/certpath/CertId.java b/src/share/classes/sun/security/provider/certpath/CertId.java index 1ee63949964452c1217897df50d2d8beaed8b2f9..20e9aa2a789a1416b5e76219250557388d5c0924 100644 --- a/src/share/classes/sun/security/provider/certpath/CertId.java +++ b/src/share/classes/sun/security/provider/certpath/CertId.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 @@ -25,9 +25,11 @@ package sun.security.provider.certpath; -import java.io.*; +import java.io.IOException; import java.math.BigInteger; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; import java.util.Arrays; import sun.misc.HexDumpEncoder; import sun.security.x509.*; @@ -54,21 +56,28 @@ import sun.security.util.*; public class CertId { private static final boolean debug = false; - private AlgorithmId hashAlgId; - private byte[] issuerNameHash; - private byte[] issuerKeyHash; - private SerialNumber certSerialNumber; + private static final AlgorithmId SHA1_ALGID + = new AlgorithmId(AlgorithmId.SHA_oid); + private final AlgorithmId hashAlgId; + private final byte[] issuerNameHash; + private final byte[] issuerKeyHash; + private final SerialNumber certSerialNumber; private int myhash = -1; // hashcode for this CertId /** * Creates a CertId. The hash algorithm used is SHA-1. */ - public CertId(X509CertImpl issuerCert, SerialNumber serialNumber) - throws Exception { + public CertId(X509Certificate issuerCert, SerialNumber serialNumber) + throws IOException { // compute issuerNameHash - MessageDigest md = MessageDigest.getInstance("SHA1"); - hashAlgId = AlgorithmId.get("SHA1"); + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException nsae) { + throw new IOException("Unable to create CertId", nsae); + } + hashAlgId = SHA1_ALGID; md.update(issuerCert.getSubjectX500Principal().getEncoded()); issuerNameHash = md.digest(); @@ -90,6 +99,7 @@ public class CertId { encoder.encode(issuerNameHash)); System.out.println("issuerKeyHash is " + encoder.encode(issuerKeyHash)); + System.out.println("SerialNumber is " + serialNumber.getNumber()); } } @@ -97,7 +107,6 @@ public class CertId { * Creates a CertId from its ASN.1 DER encoding. */ public CertId(DerInputStream derIn) throws IOException { - hashAlgId = AlgorithmId.parse(derIn.getDerValue()); issuerNameHash = derIn.getOctetString(); issuerKeyHash = derIn.getOctetString(); @@ -157,7 +166,7 @@ public class CertId { * * @return the hashcode value. */ - public int hashCode() { + @Override public int hashCode() { if (myhash == -1) { myhash = hashAlgId.hashCode(); for (int i = 0; i < issuerNameHash.length; i++) { @@ -180,8 +189,7 @@ public class CertId { * @param other the object to test for equality with this object. * @return true if the objects are considered equal, false otherwise. */ - public boolean equals(Object other) { - + @Override public boolean equals(Object other) { if (this == other) { return true; } @@ -203,7 +211,7 @@ public class CertId { /** * Create a string representation of the CertId. */ - public String toString() { + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("CertId \n"); sb.append("Algorithm: " + hashAlgId.toString() +"\n"); diff --git a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java b/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java index b462dd5ba0870486ad0e3fe1554e82b63175a3bc..18845113edb39d7422d9b0ada49ff1d89e7b9834 100644 --- a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java +++ b/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java @@ -80,6 +80,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker { { false, false, false, false, false, false, true }; private static final boolean[] ALL_REASONS = {true, true, true, true, true, true, true, true, true}; + private boolean mOnlyEECert = false; // Maximum clock skew in milliseconds (15 minutes) allowed when checking // validity of CRLs @@ -114,6 +115,12 @@ class CrlRevocationChecker extends PKIXCertPathChecker { CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params, Collection certs) throws CertPathValidatorException { + this(anchor, params, certs, false); + } + + CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params, + Collection certs, boolean onlyEECert) + throws CertPathValidatorException { mAnchor = anchor; mParams = params; mStores = new ArrayList(params.getCertStores()); @@ -133,6 +140,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker { } Date testDate = params.getDate(); mCurrentTime = (testDate != null ? testDate : new Date()); + mOnlyEECert = onlyEECert; init(false); } @@ -264,6 +272,13 @@ class CrlRevocationChecker extends PKIXCertPathChecker { " ---checking " + msg + "..."); } + if (mOnlyEECert && currCert.getBasicConstraints() != -1) { + if (debug != null) { + debug.println("Skipping revocation check, not end entity cert"); + } + return; + } + // reject circular dependencies - RFC 3280 is not explicit on how // to handle this, so we feel it is safest to reject them until // the issue is resolved in the PKIX WG. diff --git a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index 39ee1f1dad6395171e9e8bceb7583e56b98e7543..dea521a4a19c21215b05821870a29712374ae15d 100644 --- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -32,7 +32,7 @@ import java.security.*; import java.security.cert.*; import javax.security.auth.x500.X500Principal; -import sun.security.action.GetPropertyAction; +import sun.security.action.GetBooleanAction; import sun.security.util.Debug; import sun.security.util.DerOutputStream; import sun.security.x509.*; @@ -62,28 +62,8 @@ class DistributionPointFetcher { * extension shall be enabled. Currently disabled by default for * compatibility and legal reasons. */ - private final static boolean USE_CRLDP = - getBooleanProperty("com.sun.security.enableCRLDP", false); - - /** - * Return the value of the boolean System property propName. - */ - public static boolean getBooleanProperty(String propName, - boolean defaultValue) { - // if set, require value of either true or false - String b = AccessController.doPrivileged( - new GetPropertyAction(propName)); - if (b == null) { - return defaultValue; - } else if (b.equalsIgnoreCase("false")) { - return false; - } else if (b.equalsIgnoreCase("true")) { - return true; - } else { - throw new RuntimeException("Value of " + propName - + " must either be 'true' or 'false'"); - } - } + private final static boolean USE_CRLDP = AccessController.doPrivileged + (new GetBooleanAction("com.sun.security.enableCRLDP")); // singleton instance private static final DistributionPointFetcher INSTANCE = diff --git a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 393a7663c91a23ab7b58aae5ff3cb52d3134b4ff..41fe50d66b706466b089077703facb7a96cbe7f7 100644 --- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -82,6 +82,7 @@ class ForwardBuilder extends Builder { TrustAnchor trustAnchor; private Comparator comparator; private boolean searchAllCertStores = true; + private boolean onlyEECert = false; /** * Initialize the builder with the input parameters. @@ -89,7 +90,8 @@ class ForwardBuilder extends Builder { * @param params the parameter set used to build a certification path */ ForwardBuilder(PKIXBuilderParameters buildParams, - X500Principal targetSubjectDN, boolean searchAllCertStores) + X500Principal targetSubjectDN, boolean searchAllCertStores, + boolean onlyEECert) { super(buildParams, targetSubjectDN); @@ -108,6 +110,7 @@ class ForwardBuilder extends Builder { } comparator = new PKIXCertComparator(trustedSubjectDNs); this.searchAllCertStores = searchAllCertStores; + this.onlyEECert = onlyEECert; } /** @@ -875,8 +878,8 @@ class ForwardBuilder extends Builder { /* Check revocation if it is enabled */ if (buildParams.isRevocationEnabled()) { try { - CrlRevocationChecker crlChecker = - new CrlRevocationChecker(anchor, buildParams); + CrlRevocationChecker crlChecker = new CrlRevocationChecker + (anchor, buildParams, null, onlyEECert); crlChecker.check(cert, anchor.getCAPublicKey(), true); } catch (CertPathValidatorException cpve) { if (debug != null) { diff --git a/src/share/classes/sun/security/provider/certpath/OCSP.java b/src/share/classes/sun/security/provider/certpath/OCSP.java new file mode 100644 index 0000000000000000000000000000000000000000..2665de6d6801c05cd8231b9c4090d5ffa69046af --- /dev/null +++ b/src/share/classes/sun/security/provider/certpath/OCSP.java @@ -0,0 +1,329 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package sun.security.provider.certpath; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URL; +import java.net.HttpURLConnection; +import java.security.cert.CertificateException; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CRLReason; +import java.security.cert.Extension; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static sun.security.provider.certpath.OCSPResponse.*; +import sun.security.util.Debug; +import sun.security.x509.AccessDescription; +import sun.security.x509.AuthorityInfoAccessExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNameInterface; +import sun.security.x509.URIName; +import sun.security.x509.X509CertImpl; + +/** + * This is a class that checks the revocation status of a certificate(s) using + * OCSP. It is not a PKIXCertPathChecker and therefore can be used outside of + * the CertPathValidator framework. It is useful when you want to + * just check the revocation status of a certificate, and you don't want to + * incur the overhead of validating all of the certificates in the + * associated certificate chain. + * + * @author Sean Mullan + */ +public final class OCSP { + + private static final Debug debug = Debug.getInstance("certpath"); + + private OCSP() {} + + /** + * Obtains the revocation status of a certificate using OCSP using the most + * common defaults. The OCSP responder URI is retrieved from the + * certificate's AIA extension. The OCSP responder certificate is assumed + * to be the issuer's certificate (or issued by the issuer CA). + * + * @param cert the certificate to be checked + * @param issuerCert the issuer certificate + * @return the RevocationStatus + * @throws IOException if there is an exception connecting to or + * communicating with the OCSP responder + * @throws CertPathValidatorException if an exception occurs while + * encoding the OCSP Request or validating the OCSP Response + */ + public static RevocationStatus check(X509Certificate cert, + X509Certificate issuerCert) + throws IOException, CertPathValidatorException { + CertId certId = null; + URI responderURI = null; + try { + X509CertImpl certImpl = X509CertImpl.toImpl(cert); + responderURI = getResponderURI(certImpl); + if (responderURI == null) { + throw new CertPathValidatorException + ("No OCSP Responder URI in certificate"); + } + certId = new CertId(issuerCert, certImpl.getSerialNumberObject()); + } catch (CertificateException ce) { + throw new CertPathValidatorException + ("Exception while encoding OCSPRequest", ce); + } catch (IOException ioe) { + throw new CertPathValidatorException + ("Exception while encoding OCSPRequest", ioe); + } + OCSPResponse ocspResponse = check(Collections.singletonList(certId), + responderURI, issuerCert, null); + return (RevocationStatus) ocspResponse.getSingleResponse(certId); + } + + /** + * Obtains the revocation status of a certificate using OCSP. + * + * @param cert the certificate to be checked + * @param issuerCert the issuer certificate + * @param responderURI the URI of the OCSP responder + * @param responderCert the OCSP responder's certificate + * @param date the time the validity of the OCSP responder's certificate + * should be checked against. If null, the current time is used. + * @return the RevocationStatus + * @throws IOException if there is an exception connecting to or + * communicating with the OCSP responder + * @throws CertPathValidatorException if an exception occurs while + * encoding the OCSP Request or validating the OCSP Response + */ + public static RevocationStatus check(X509Certificate cert, + X509Certificate issuerCert, URI responderURI, X509Certificate + responderCert, Date date) + throws IOException, CertPathValidatorException { + CertId certId = null; + try { + X509CertImpl certImpl = X509CertImpl.toImpl(cert); + certId = new CertId(issuerCert, certImpl.getSerialNumberObject()); + } catch (CertificateException ce) { + throw new CertPathValidatorException + ("Exception while encoding OCSPRequest", ce); + } catch (IOException ioe) { + throw new CertPathValidatorException + ("Exception while encoding OCSPRequest", ioe); + } + OCSPResponse ocspResponse = check(Collections.singletonList(certId), + responderURI, responderCert, date); + return (RevocationStatus) ocspResponse.getSingleResponse(certId); + } + + /** + * Checks the revocation status of a list of certificates using OCSP. + * + * @param certs the CertIds to be checked + * @param responderURI the URI of the OCSP responder + * @param responderCert the OCSP responder's certificate + * @param date the time the validity of the OCSP responder's certificate + * should be checked against. If null, the current time is used. + * @return the OCSPResponse + * @throws IOException if there is an exception connecting to or + * communicating with the OCSP responder + * @throws CertPathValidatorException if an exception occurs while + * encoding the OCSP Request or validating the OCSP Response + */ + static OCSPResponse check(List certIds, URI responderURI, + X509Certificate responderCert, Date date) + throws IOException, CertPathValidatorException { + + byte[] bytes = null; + try { + OCSPRequest request = new OCSPRequest(certIds); + bytes = request.encodeBytes(); + } catch (IOException ioe) { + throw new CertPathValidatorException + ("Exception while encoding OCSPRequest", ioe); + } + + InputStream in = null; + OutputStream out = null; + byte[] response = null; + try { + URL url = responderURI.toURL(); + if (debug != null) { + debug.println("connecting to OCSP service at: " + url); + } + HttpURLConnection con = (HttpURLConnection)url.openConnection(); + con.setDoOutput(true); + con.setDoInput(true); + con.setRequestMethod("POST"); + con.setRequestProperty + ("Content-type", "application/ocsp-request"); + con.setRequestProperty + ("Content-length", String.valueOf(bytes.length)); + out = con.getOutputStream(); + out.write(bytes); + out.flush(); + // Check the response + if (debug != null && + con.getResponseCode() != HttpURLConnection.HTTP_OK) { + debug.println("Received HTTP error: " + con.getResponseCode() + + " - " + con.getResponseMessage()); + } + in = con.getInputStream(); + int contentLength = con.getContentLength(); + if (contentLength == -1) { + contentLength = Integer.MAX_VALUE; + } + response = new byte[contentLength > 2048 ? 2048 : contentLength]; + int total = 0; + while (total < contentLength) { + int count = in.read(response, total, response.length - total); + if (count < 0) + break; + + total += count; + if (total >= response.length && total < contentLength) { + response = Arrays.copyOf(response, total * 2); + } + } + response = Arrays.copyOf(response, total); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ioe) { + throw ioe; + } + } + if (out != null) { + try { + out.close(); + } catch (IOException ioe) { + throw ioe; + } + } + } + + OCSPResponse ocspResponse = null; + try { + ocspResponse = new OCSPResponse(response, date, responderCert); + } catch (IOException ioe) { + // response decoding exception + throw new CertPathValidatorException(ioe); + } + if (ocspResponse.getResponseStatus() != ResponseStatus.SUCCESSFUL) { + throw new CertPathValidatorException + ("OCSP response error: " + ocspResponse.getResponseStatus()); + } + + // Check that the response includes a response for all of the + // certs that were supplied in the request + for (CertId certId : certIds) { + SingleResponse sr = ocspResponse.getSingleResponse(certId); + if (sr == null) { + if (debug != null) { + debug.println("No response found for CertId: " + certId); + } + throw new CertPathValidatorException( + "OCSP response does not include a response for a " + + "certificate supplied in the OCSP request"); + } + if (debug != null) { + debug.println("Status of certificate (with serial number " + + certId.getSerialNumber() + ") is: " + sr.getCertStatus()); + } + } + return ocspResponse; + } + + /** + * Returns the URI of the OCSP Responder as specified in the + * certificate's Authority Information Access extension, or null if + * not specified. + * + * @param cert the certificate + * @return the URI of the OCSP Responder, or null if not specified + */ + public static URI getResponderURI(X509Certificate cert) { + try { + return getResponderURI(X509CertImpl.toImpl(cert)); + } catch (CertificateException ce) { + // treat this case as if the cert had no extension + return null; + } + } + + static URI getResponderURI(X509CertImpl certImpl) { + + // Examine the certificate's AuthorityInfoAccess extension + AuthorityInfoAccessExtension aia = + certImpl.getAuthorityInfoAccessExtension(); + if (aia == null) { + return null; + } + + List descriptions = aia.getAccessDescriptions(); + for (AccessDescription description : descriptions) { + if (description.getAccessMethod().equals( + AccessDescription.Ad_OCSP_Id)) { + + GeneralName generalName = description.getAccessLocation(); + if (generalName.getType() == GeneralNameInterface.NAME_URI) { + URIName uri = (URIName) generalName.getName(); + return uri.getURI(); + } + } + } + return null; + } + + /** + * The Revocation Status of a certificate. + */ + public static interface RevocationStatus { + public enum CertStatus { GOOD, REVOKED, UNKNOWN }; + + /** + * Returns the revocation status. + */ + CertStatus getCertStatus(); + /** + * Returns the time when the certificate was revoked, or null + * if it has not been revoked. + */ + Date getRevocationTime(); + /** + * Returns the reason the certificate was revoked, or null if it + * has not been revoked. + */ + CRLReason getRevocationReason(); + + /** + * Returns a Map of additional extensions. + */ + Map getSingleExtensions(); + } +} diff --git a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java index 04e0649d8ffc0a5188cca9dd0baf2d6410177f17..6f72c7ec185dc9e2fe5c80889dd75ff52fe52b8e 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java +++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java @@ -25,19 +25,20 @@ package sun.security.provider.certpath; -import java.io.*; +import java.io.IOException; import java.math.BigInteger; import java.util.*; import java.security.AccessController; -import java.security.Principal; import java.security.PrivilegedAction; import java.security.Security; import java.security.cert.*; import java.security.cert.CertPathValidatorException.BasicReason; -import java.net.*; +import java.net.URI; +import java.net.URISyntaxException; import javax.security.auth.x500.X500Principal; -import sun.security.util.*; +import static sun.security.provider.certpath.OCSP.*; +import sun.security.util.Debug; import sun.security.x509.*; /** @@ -50,27 +51,18 @@ import sun.security.x509.*; */ class OCSPChecker extends PKIXCertPathChecker { - public static final String OCSP_ENABLE_PROP = "ocsp.enable"; - public static final String OCSP_URL_PROP = "ocsp.responderURL"; - public static final String OCSP_CERT_SUBJECT_PROP = + static final String OCSP_ENABLE_PROP = "ocsp.enable"; + static final String OCSP_URL_PROP = "ocsp.responderURL"; + static final String OCSP_CERT_SUBJECT_PROP = "ocsp.responderCertSubjectName"; - public static final String OCSP_CERT_ISSUER_PROP = - "ocsp.responderCertIssuerName"; - public static final String OCSP_CERT_NUMBER_PROP = + static final String OCSP_CERT_ISSUER_PROP = "ocsp.responderCertIssuerName"; + static final String OCSP_CERT_NUMBER_PROP = "ocsp.responderCertSerialNumber"; private static final String HEX_DIGITS = "0123456789ABCDEFabcdef"; private static final Debug DEBUG = Debug.getInstance("certpath"); private static final boolean dump = false; - // Supported extensions - private static final int OCSP_NONCE_DATA[] = - { 1, 3, 6, 1, 5, 5, 7, 48, 1, 2 }; - private static final ObjectIdentifier OCSP_NONCE_OID; - static { - OCSP_NONCE_OID = ObjectIdentifier.newInternal(OCSP_NONCE_DATA); - } - private int remainingCerts; private X509Certificate[] certs; @@ -79,19 +71,26 @@ class OCSPChecker extends PKIXCertPathChecker { private PKIXParameters pkixParams; + private boolean onlyEECert = false; + /** * Default Constructor * * @param certPath the X509 certification path * @param pkixParams the input PKIX parameter set - * @exception CertPathValidatorException Exception thrown if cert path - * does not validate. + * @throws CertPathValidatorException if OCSPChecker can not be created */ OCSPChecker(CertPath certPath, PKIXParameters pkixParams) throws CertPathValidatorException { + this(certPath, pkixParams, false); + } + + OCSPChecker(CertPath certPath, PKIXParameters pkixParams, boolean onlyEECert) + throws CertPathValidatorException { this.cp = certPath; this.pkixParams = pkixParams; + this.onlyEECert = onlyEECert; List tmp = cp.getCertificates(); certs = tmp.toArray(new X509Certificate[tmp.size()]); init(false); @@ -101,6 +100,7 @@ class OCSPChecker extends PKIXCertPathChecker { * Initializes the internal state of the checker from parameters * specified in the constructor */ + @Override public void init(boolean forward) throws CertPathValidatorException { if (!forward) { remainingCerts = certs.length + 1; @@ -110,11 +110,11 @@ class OCSPChecker extends PKIXCertPathChecker { } } - public boolean isForwardCheckingSupported() { + @Override public boolean isForwardCheckingSupported() { return false; } - public Set getSupportedExtensions() { + @Override public Set getSupportedExtensions() { return Collections.emptySet(); } @@ -127,300 +127,233 @@ class OCSPChecker extends PKIXCertPathChecker { * @exception CertPathValidatorException Exception is thrown if the * certificate has been revoked. */ + @Override public void check(Certificate cert, Collection unresolvedCritExts) throws CertPathValidatorException { - InputStream in = null; - OutputStream out = null; - // Decrement the certificate counter remainingCerts--; + X509CertImpl currCertImpl = null; try { - X509Certificate responderCert = null; - boolean seekResponderCert = false; - X500Principal responderSubjectName = null; - X500Principal responderIssuerName = null; - BigInteger responderSerialNumber = null; - - boolean seekIssuerCert = true; - X509CertImpl issuerCertImpl = null; - X509CertImpl currCertImpl = - X509CertImpl.toImpl((X509Certificate)cert); - - /* - * OCSP security property values, in the following order: - * 1. ocsp.responderURL - * 2. ocsp.responderCertSubjectName - * 3. ocsp.responderCertIssuerName - * 4. ocsp.responderCertSerialNumber - */ - String[] properties = getOCSPProperties(); - - // Check whether OCSP is feasible before seeking cert information - URL url = getOCSPServerURL(currCertImpl, properties); - - // When responder's subject name is set then the issuer/serial - // properties are ignored - if (properties[1] != null) { - responderSubjectName = new X500Principal(properties[1]); - - } else if (properties[2] != null && properties[3] != null) { - responderIssuerName = new X500Principal(properties[2]); - // remove colon or space separators - String value = stripOutSeparators(properties[3]); - responderSerialNumber = new BigInteger(value, 16); - - } else if (properties[2] != null || properties[3] != null) { - throw new CertPathValidatorException( - "Must specify both ocsp.responderCertIssuerName and " + - "ocsp.responderCertSerialNumber properties"); - } - - // If the OCSP responder cert properties are set then the - // identified cert must be located in the trust anchors or - // in the cert stores. - if (responderSubjectName != null || responderIssuerName != null) { - seekResponderCert = true; - } + currCertImpl = X509CertImpl.toImpl((X509Certificate)cert); + } catch (CertificateException ce) { + throw new CertPathValidatorException(ce); + } - // Set the issuer certificate to the next cert in the chain - // (unless we're processing the final cert). - if (remainingCerts < certs.length) { - issuerCertImpl = X509CertImpl.toImpl(certs[remainingCerts]); - seekIssuerCert = false; // done - - // By default, the OCSP responder's cert is the same as the - // issuer of the cert being validated. - if (! seekResponderCert) { - responderCert = certs[remainingCerts]; - if (DEBUG != null) { - DEBUG.println("Responder's certificate is the same " + - "as the issuer of the certificate being validated"); - } - } + if (onlyEECert && currCertImpl.getBasicConstraints() != -1) { + if (DEBUG != null) { + DEBUG.println("Skipping revocation check, not end entity cert"); } + return; + } - // Check anchor certs for: - // - the issuer cert (of the cert being validated) - // - the OCSP responder's cert - if (seekIssuerCert || seekResponderCert) { + /* + * OCSP security property values, in the following order: + * 1. ocsp.responderURL + * 2. ocsp.responderCertSubjectName + * 3. ocsp.responderCertIssuerName + * 4. ocsp.responderCertSerialNumber + */ + // should cache these properties to avoid calling every time? + String[] properties = getOCSPProperties(); + + // Check whether OCSP is feasible before seeking cert information + URI uri = getOCSPServerURI(currCertImpl, properties[0]); + + // When responder's subject name is set then the issuer/serial + // properties are ignored + X500Principal responderSubjectName = null; + X500Principal responderIssuerName = null; + BigInteger responderSerialNumber = null; + if (properties[1] != null) { + responderSubjectName = new X500Principal(properties[1]); + } else if (properties[2] != null && properties[3] != null) { + responderIssuerName = new X500Principal(properties[2]); + // remove colon or space separators + String value = stripOutSeparators(properties[3]); + responderSerialNumber = new BigInteger(value, 16); + } else if (properties[2] != null || properties[3] != null) { + throw new CertPathValidatorException( + "Must specify both ocsp.responderCertIssuerName and " + + "ocsp.responderCertSerialNumber properties"); + } - if (DEBUG != null && seekResponderCert) { - DEBUG.println("Searching trust anchors for responder's " + - "certificate"); - } + // If the OCSP responder cert properties are set then the + // identified cert must be located in the trust anchors or + // in the cert stores. + boolean seekResponderCert = false; + if (responderSubjectName != null || responderIssuerName != null) { + seekResponderCert = true; + } - // Extract the anchor certs - Iterator anchors = pkixParams.getTrustAnchors().iterator(); - if (! anchors.hasNext()) { - throw new CertPathValidatorException( - "Must specify at least one trust anchor"); + // Set the issuer certificate to the next cert in the chain + // (unless we're processing the final cert). + X509Certificate issuerCert = null; + boolean seekIssuerCert = true; + X509Certificate responderCert = null; + if (remainingCerts < certs.length) { + issuerCert = certs[remainingCerts]; + seekIssuerCert = false; // done + + // By default, the OCSP responder's cert is the same as the + // issuer of the cert being validated. + if (!seekResponderCert) { + responderCert = issuerCert; + if (DEBUG != null) { + DEBUG.println("Responder's certificate is the same " + + "as the issuer of the certificate being validated"); } + } + } - X500Principal certIssuerName = - currCertImpl.getIssuerX500Principal(); - while (anchors.hasNext() && - (seekIssuerCert || seekResponderCert)) { + // Check anchor certs for: + // - the issuer cert (of the cert being validated) + // - the OCSP responder's cert + if (seekIssuerCert || seekResponderCert) { - TrustAnchor anchor = (TrustAnchor)anchors.next(); - X509Certificate anchorCert = anchor.getTrustedCert(); - X500Principal anchorSubjectName = - anchorCert.getSubjectX500Principal(); + if (DEBUG != null && seekResponderCert) { + DEBUG.println("Searching trust anchors for responder's " + + "certificate"); + } - if (dump) { - System.out.println("Issuer DN is " + certIssuerName); - System.out.println("Subject DN is " + - anchorSubjectName); - } + // Extract the anchor certs + Iterator anchors + = pkixParams.getTrustAnchors().iterator(); + if (!anchors.hasNext()) { + throw new CertPathValidatorException( + "Must specify at least one trust anchor"); + } - // Check if anchor cert is the issuer cert - if (seekIssuerCert && - certIssuerName.equals(anchorSubjectName)) { + X500Principal certIssuerName = + currCertImpl.getIssuerX500Principal(); + while (anchors.hasNext() && (seekIssuerCert || seekResponderCert)) { - issuerCertImpl = X509CertImpl.toImpl(anchorCert); - seekIssuerCert = false; // done + TrustAnchor anchor = anchors.next(); + X509Certificate anchorCert = anchor.getTrustedCert(); + X500Principal anchorSubjectName = + anchorCert.getSubjectX500Principal(); - // By default, the OCSP responder's cert is the same as - // the issuer of the cert being validated. - if (! seekResponderCert && responderCert == null) { - responderCert = anchorCert; - if (DEBUG != null) { - DEBUG.println("Responder's certificate is the" + - " same as the issuer of the certificate " + - "being validated"); - } - } - } + if (dump) { + System.out.println("Issuer DN is " + certIssuerName); + System.out.println("Subject DN is " + anchorSubjectName); + } - // Check if anchor cert is the responder cert - if (seekResponderCert) { - // Satisfy the responder subject name property only, or - // satisfy the responder issuer name and serial number - // properties only - if ((responderSubjectName != null && - responderSubjectName.equals(anchorSubjectName)) || - (responderIssuerName != null && - responderSerialNumber != null && - responderIssuerName.equals( - anchorCert.getIssuerX500Principal()) && - responderSerialNumber.equals( - anchorCert.getSerialNumber()))) { - - responderCert = anchorCert; - seekResponderCert = false; // done + // Check if anchor cert is the issuer cert + if (seekIssuerCert && + certIssuerName.equals(anchorSubjectName)) { + + issuerCert = anchorCert; + seekIssuerCert = false; // done + + // By default, the OCSP responder's cert is the same as + // the issuer of the cert being validated. + if (!seekResponderCert && responderCert == null) { + responderCert = anchorCert; + if (DEBUG != null) { + DEBUG.println("Responder's certificate is the" + + " same as the issuer of the certificate " + + "being validated"); } } } - if (issuerCertImpl == null) { - throw new CertPathValidatorException( - "No trusted certificate for " + - currCertImpl.getIssuerDN()); - } - // Check cert stores if responder cert has not yet been found + // Check if anchor cert is the responder cert if (seekResponderCert) { - if (DEBUG != null) { - DEBUG.println("Searching cert stores for responder's " + - "certificate"); - } - X509CertSelector filter = null; - if (responderSubjectName != null) { - filter = new X509CertSelector(); - filter.setSubject(responderSubjectName.getName()); - } else if (responderIssuerName != null && - responderSerialNumber != null) { - filter = new X509CertSelector(); - filter.setIssuer(responderIssuerName.getName()); - filter.setSerialNumber(responderSerialNumber); - } - if (filter != null) { - List certStores = pkixParams.getCertStores(); - for (CertStore certStore : certStores) { - Iterator i = - certStore.getCertificates(filter).iterator(); - if (i.hasNext()) { - responderCert = (X509Certificate) i.next(); - seekResponderCert = false; // done - break; - } - } + // Satisfy the responder subject name property only, or + // satisfy the responder issuer name and serial number + // properties only + if ((responderSubjectName != null && + responderSubjectName.equals(anchorSubjectName)) || + (responderIssuerName != null && + responderSerialNumber != null && + responderIssuerName.equals( + anchorCert.getIssuerX500Principal()) && + responderSerialNumber.equals( + anchorCert.getSerialNumber()))) { + + responderCert = anchorCert; + seekResponderCert = false; // done } } } - - // Could not find the certificate identified in the OCSP properties - if (seekResponderCert) { + if (issuerCert == null) { throw new CertPathValidatorException( - "Cannot find the responder's certificate " + - "(set using the OCSP security properties)."); + "No trusted certificate for " + currCertImpl.getIssuerDN()); } - // Construct an OCSP Request - OCSPRequest ocspRequest = - new OCSPRequest(currCertImpl, issuerCertImpl); - - // Use the URL to the OCSP service that was created earlier - HttpURLConnection con = (HttpURLConnection)url.openConnection(); - if (DEBUG != null) { - DEBUG.println("connecting to OCSP service at: " + url); - } - - // Indicate that both input and output will be performed, - // that the method is POST, and that the content length is - // the length of the byte array - - con.setDoOutput(true); - con.setDoInput(true); - con.setRequestMethod("POST"); - con.setRequestProperty("Content-type", "application/ocsp-request"); - byte[] bytes = ocspRequest.encodeBytes(); - CertId certId = ocspRequest.getCertId(); - - con.setRequestProperty("Content-length", - String.valueOf(bytes.length)); - out = con.getOutputStream(); - out.write(bytes); - out.flush(); - - // Check the response - if (DEBUG != null && - con.getResponseCode() != HttpURLConnection.HTTP_OK) { - DEBUG.println("Received HTTP error: " + con.getResponseCode() + - " - " + con.getResponseMessage()); - } - in = con.getInputStream(); - - byte[] response = null; - int total = 0; - int contentLength = con.getContentLength(); - if (contentLength != -1) { - response = new byte[contentLength]; - } else { - response = new byte[2048]; - contentLength = Integer.MAX_VALUE; - } - - while (total < contentLength) { - int count = in.read(response, total, response.length - total); - if (count < 0) - break; - - total += count; - if (total >= response.length && total < contentLength) { - response = Arrays.copyOf(response, total * 2); + // Check cert stores if responder cert has not yet been found + if (seekResponderCert) { + if (DEBUG != null) { + DEBUG.println("Searching cert stores for responder's " + + "certificate"); + } + X509CertSelector filter = null; + if (responderSubjectName != null) { + filter = new X509CertSelector(); + filter.setSubject(responderSubjectName); + } else if (responderIssuerName != null && + responderSerialNumber != null) { + filter = new X509CertSelector(); + filter.setIssuer(responderIssuerName); + filter.setSerialNumber(responderSerialNumber); + } + if (filter != null) { + List certStores = pkixParams.getCertStores(); + for (CertStore certStore : certStores) { + Iterator i = null; + try { + i = certStore.getCertificates(filter).iterator(); + } catch (CertStoreException cse) { + // ignore and try next certStore + if (DEBUG != null) { + DEBUG.println("CertStore exception:" + cse); + } + continue; + } + if (i.hasNext()) { + responderCert = (X509Certificate) i.next(); + seekResponderCert = false; // done + break; + } + } } } - response = Arrays.copyOf(response, total); - - OCSPResponse ocspResponse = new OCSPResponse(response, pkixParams, - responderCert); - // Check that response applies to the cert that was supplied - if (! certId.equals(ocspResponse.getCertId())) { - throw new CertPathValidatorException( - "Certificate in the OCSP response does not match the " + - "certificate supplied in the OCSP request."); - } - SerialNumber serialNumber = currCertImpl.getSerialNumberObject(); - int certOCSPStatus = ocspResponse.getCertStatus(serialNumber); + } - if (DEBUG != null) { - DEBUG.println("Status of certificate (with serial number " + - serialNumber.getNumber() + ") is: " + - OCSPResponse.certStatusToText(certOCSPStatus)); - } + // Could not find the certificate identified in the OCSP properties + if (seekResponderCert) { + throw new CertPathValidatorException( + "Cannot find the responder's certificate " + + "(set using the OCSP security properties)."); + } - if (certOCSPStatus == OCSPResponse.CERT_STATUS_REVOKED) { - Throwable t = new CertificateRevokedException( - ocspResponse.getRevocationTime(), - ocspResponse.getRevocationReason(), - responderCert.getSubjectX500Principal(), - ocspResponse.getSingleExtensions()); - throw new CertPathValidatorException(t.getMessage(), t, - null, -1, BasicReason.REVOKED); + CertId certId = null; + OCSPResponse response = null; + try { + certId = new CertId + (issuerCert, currCertImpl.getSerialNumberObject()); + response = OCSP.check(Collections.singletonList(certId), uri, + responderCert, pkixParams.getDate()); + } catch (IOException ioe) { + // should allow this to pass if network failures are acceptable + throw new CertPathValidatorException + ("Unable to send OCSP request", ioe); + } - } else if (certOCSPStatus == OCSPResponse.CERT_STATUS_UNKNOWN) { - throw new CertPathValidatorException( - "Certificate's revocation status is unknown", null, cp, - remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS); - } - } catch (Exception e) { - throw new CertPathValidatorException(e); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ioe) { - throw new CertPathValidatorException(ioe); - } - } - if (out != null) { - try { - out.close(); - } catch (IOException ioe) { - throw new CertPathValidatorException(ioe); - } - } + RevocationStatus rs = (RevocationStatus) response.getSingleResponse(certId); + RevocationStatus.CertStatus certStatus = rs.getCertStatus(); + if (certStatus == RevocationStatus.CertStatus.REVOKED) { + Throwable t = new CertificateRevokedException( + rs.getRevocationTime(), rs.getRevocationReason(), + responderCert.getSubjectX500Principal(), + rs.getSingleExtensions()); + throw new CertPathValidatorException(t.getMessage(), t, + null, -1, BasicReason.REVOKED); + } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) { + throw new CertPathValidatorException( + "Certificate's revocation status is unknown", null, cp, + remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS); } } @@ -431,20 +364,18 @@ class OCSPChecker extends PKIXCertPathChecker { * 3. ocsp.responderCertIssuerName * 4. ocsp.responderCertSerialNumber */ - private static URL getOCSPServerURL(X509CertImpl currCertImpl, - String[] properties) - throws CertificateParsingException, CertPathValidatorException { - - if (properties[0] != null) { - try { - return new URL(properties[0]); - } catch (java.net.MalformedURLException e) { + private static URI getOCSPServerURI(X509CertImpl currCertImpl, + String responderURL) throws CertPathValidatorException { + + if (responderURL != null) { + try { + return new URI(responderURL); + } catch (URISyntaxException e) { throw new CertPathValidatorException(e); - } + } } // Examine the certificate's AuthorityInfoAccess extension - AuthorityInfoAccessExtension aia = currCertImpl.getAuthorityInfoAccessExtension(); if (aia == null) { @@ -459,13 +390,8 @@ class OCSPChecker extends PKIXCertPathChecker { GeneralName generalName = description.getAccessLocation(); if (generalName.getType() == GeneralNameInterface.NAME_URI) { - try { - URIName uri = (URIName) generalName.getName(); - return (new URL(uri.getName())); - - } catch (java.net.MalformedURLException e) { - throw new CertPathValidatorException(e); - } + URIName uri = (URIName) generalName.getName(); + return uri.getURI(); } } } diff --git a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java index b7350b55e9bc194541b312dccc0ae83f2aa15a79..393ac6f0e73d6bd85177d6e4196106a80a031d01 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java +++ b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 @@ -26,9 +26,9 @@ package sun.security.provider.certpath; import java.io.IOException; -import java.security.cert.CertPathValidatorException; +import java.util.Collections; +import java.util.List; import sun.misc.HexDumpEncoder; -import sun.security.x509.*; import sun.security.util.*; /** @@ -77,47 +77,33 @@ class OCSPRequest { private static final Debug debug = Debug.getInstance("certpath"); private static final boolean dump = false; - // Serial number of the certificates to be checked for revocation - private SerialNumber serialNumber; - - // Issuer's certificate (for computing certId hash values) - private X509CertImpl issuerCert; - - // CertId of the certificate to be checked - private CertId certId = null; + // List of request CertIds + private final List certIds; /* * Constructs an OCSPRequest. This constructor is used * to construct an unsigned OCSP Request for a single user cert. */ - // used by OCSPChecker - OCSPRequest(X509CertImpl userCert, X509CertImpl issuerCert) - throws CertPathValidatorException { + OCSPRequest(CertId certId) { + this.certIds = Collections.singletonList(certId); + } - if (issuerCert == null) { - throw new CertPathValidatorException("Null IssuerCertificate"); - } - this.issuerCert = issuerCert; - serialNumber = userCert.getSerialNumberObject(); + OCSPRequest(List certIds) { + this.certIds = certIds; } - // used by OCSPChecker byte[] encodeBytes() throws IOException { // encode tbsRequest DerOutputStream tmp = new DerOutputStream(); - DerOutputStream derSingleReqList = new DerOutputStream(); - SingleRequest singleRequest = null; - - try { - singleRequest = new SingleRequest(issuerCert, serialNumber); - } catch (Exception e) { - throw new IOException("Error encoding OCSP request"); + DerOutputStream requestsOut = new DerOutputStream(); + for (CertId certId : certIds) { + DerOutputStream certIdOut = new DerOutputStream(); + certId.encode(certIdOut); + requestsOut.write(DerValue.tag_Sequence, certIdOut); } - certId = singleRequest.getCertId(); - singleRequest.encode(derSingleReqList); - tmp.write(DerValue.tag_Sequence, derSingleReqList); + tmp.write(DerValue.tag_Sequence, requestsOut); // No extensions supported DerOutputStream tbsRequest = new DerOutputStream(); tbsRequest.write(DerValue.tag_Sequence, tmp); @@ -130,35 +116,14 @@ class OCSPRequest { if (dump) { HexDumpEncoder hexEnc = new HexDumpEncoder(); - System.out.println ("OCSPRequest bytes are... "); + System.out.println("OCSPRequest bytes are... "); System.out.println(hexEnc.encode(bytes)); } - return(bytes); - } - - // used by OCSPChecker - CertId getCertId() { - return certId; + return bytes; } - private static class SingleRequest { - private CertId certId; - - // No extensions are set - - private SingleRequest(X509CertImpl cert, SerialNumber serialNo) throws Exception { - certId = new CertId(cert, serialNo); - } - - private void encode(DerOutputStream out) throws IOException { - DerOutputStream tmp = new DerOutputStream(); - certId.encode(tmp); - out.write(DerValue.tag_Sequence, tmp); - } - - private CertId getCertId() { - return certId; - } + List getCertIds() { + return certIds; } } diff --git a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java index cdadc45f66c0c4da21bbcb465ff33c636bf2a276..e7b148fbc7cae379c925082ffd5e6fb24d77b206 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -28,17 +28,16 @@ package sun.security.provider.certpath; import java.io.*; import java.math.BigInteger; import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; import java.security.cert.CertPathValidatorException; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; -import java.security.cert.PKIXParameters; -import javax.security.auth.x500.X500Principal; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.Iterator; import sun.misc.HexDumpEncoder; import sun.security.x509.*; import sun.security.util.*; @@ -113,32 +112,29 @@ import sun.security.util.*; * @author Ram Marti */ -class OCSPResponse { +public final class OCSPResponse { - // Certificate status CHOICE - public static final int CERT_STATUS_GOOD = 0; - public static final int CERT_STATUS_REVOKED = 1; - public static final int CERT_STATUS_UNKNOWN = 2; + public enum ResponseStatus { + SUCCESSFUL, // Response has valid confirmations + MALFORMED_REQUEST, // Illegal confirmation request + INTERNAL_ERROR, // Internal error in issuer + TRY_LATER, // Try again later + UNUSED, // is not used + SIG_REQUIRED, // Must sign the request + UNAUTHORIZED // Request unauthorized + }; + private static ResponseStatus[] rsvalues = ResponseStatus.values(); private static final Debug DEBUG = Debug.getInstance("certpath"); private static final boolean dump = false; - private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID; - private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID; - static { - ObjectIdentifier tmp1 = null; - ObjectIdentifier tmp2 = null; - try { - tmp1 = new ObjectIdentifier("1.3.6.1.5.5.7.48.1.1"); - tmp2 = new ObjectIdentifier("1.3.6.1.5.5.7.48.1.2"); - } catch (Exception e) { - // should not happen; log and exit - } - OCSP_BASIC_RESPONSE_OID = tmp1; - OCSP_NONCE_EXTENSION_OID = tmp2; - } + private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID = + ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1}); + private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID = + ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 2}); - // OCSP response status code - private static final int OCSP_RESPONSE_OK = 0; + private static final int CERT_STATUS_GOOD = 0; + private static final int CERT_STATUS_REVOKED = 1; + private static final int CERT_STATUS_UNKNOWN = 2; // ResponderID CHOICE tags private static final int NAME_TAG = 1; @@ -147,7 +143,8 @@ class OCSPResponse { // Object identifier for the OCSPSigning key purpose private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9"; - private SingleResponse singleResponse; + private final ResponseStatus responseStatus; + private final Map singleResponseMap; // Maximum clock skew in milliseconds (15 minutes) allowed when checking // validity of OCSP responses @@ -159,289 +156,289 @@ class OCSPResponse { /* * Create an OCSP response from its ASN.1 DER encoding. */ - // used by OCSPChecker - OCSPResponse(byte[] bytes, PKIXParameters params, + OCSPResponse(byte[] bytes, Date dateCheckedAgainst, X509Certificate responderCert) throws IOException, CertPathValidatorException { - try { - int responseStatus; - ObjectIdentifier responseType; - int version; - CertificateIssuerName responderName = null; - Date producedAtDate; - AlgorithmId sigAlgId; - byte[] ocspNonce; - - // OCSPResponse - if (dump) { - HexDumpEncoder hexEnc = new HexDumpEncoder(); - System.out.println("OCSPResponse bytes are..."); - System.out.println(hexEnc.encode(bytes)); - } - DerValue der = new DerValue(bytes); - if (der.tag != DerValue.tag_Sequence) { - throw new IOException("Bad encoding in OCSP response: " + - "expected ASN.1 SEQUENCE tag."); - } - DerInputStream derIn = der.getData(); + // OCSPResponse + if (dump) { + HexDumpEncoder hexEnc = new HexDumpEncoder(); + System.out.println("OCSPResponse bytes are..."); + System.out.println(hexEnc.encode(bytes)); + } + DerValue der = new DerValue(bytes); + if (der.tag != DerValue.tag_Sequence) { + throw new IOException("Bad encoding in OCSP response: " + + "expected ASN.1 SEQUENCE tag."); + } + DerInputStream derIn = der.getData(); + + // responseStatus + int status = derIn.getEnumerated(); + if (status >= 0 && status < rsvalues.length) { + responseStatus = rsvalues[status]; + } else { + // unspecified responseStatus + throw new IOException("Unknown OCSPResponse status: " + status); + } + if (DEBUG != null) { + DEBUG.println("OCSP response status: " + responseStatus); + } + if (responseStatus != ResponseStatus.SUCCESSFUL) { + // no need to continue, responseBytes are not set. + singleResponseMap = Collections.emptyMap(); + return; + } + + // responseBytes + der = derIn.getDerValue(); + if (!der.isContextSpecific((byte)0)) { + throw new IOException("Bad encoding in responseBytes element " + + "of OCSP response: expected ASN.1 context specific tag 0."); + } + DerValue tmp = der.data.getDerValue(); + if (tmp.tag != DerValue.tag_Sequence) { + throw new IOException("Bad encoding in responseBytes element " + + "of OCSP response: expected ASN.1 SEQUENCE tag."); + } - // responseStatus - responseStatus = derIn.getEnumerated(); + // responseType + derIn = tmp.data; + ObjectIdentifier responseType = derIn.getOID(); + if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) { if (DEBUG != null) { - DEBUG.println("OCSP response: " + - responseToText(responseStatus)); + DEBUG.println("OCSP response type: basic"); } - if (responseStatus != OCSP_RESPONSE_OK) { - throw new CertPathValidatorException( - "OCSP Response Failure: " + - responseToText(responseStatus)); + } else { + if (DEBUG != null) { + DEBUG.println("OCSP response type: " + responseType); } + throw new IOException("Unsupported OCSP response type: " + + responseType); + } - // responseBytes - der = derIn.getDerValue(); - if (! der.isContextSpecific((byte)0)) { - throw new IOException("Bad encoding in responseBytes element " + - "of OCSP response: expected ASN.1 context specific tag 0."); - }; - DerValue tmp = der.data.getDerValue(); - if (tmp.tag != DerValue.tag_Sequence) { - throw new IOException("Bad encoding in responseBytes element " + - "of OCSP response: expected ASN.1 SEQUENCE tag."); - } + // BasicOCSPResponse + DerInputStream basicOCSPResponse = + new DerInputStream(derIn.getOctetString()); - // responseType - derIn = tmp.data; - responseType = derIn.getOID(); - if (responseType.equals(OCSP_BASIC_RESPONSE_OID)) { - if (DEBUG != null) { - DEBUG.println("OCSP response type: basic"); - } - } else { - if (DEBUG != null) { - DEBUG.println("OCSP response type: " + responseType); - } - throw new IOException("Unsupported OCSP response type: " + - responseType); - } - - // BasicOCSPResponse - DerInputStream basicOCSPResponse = - new DerInputStream(derIn.getOctetString()); + DerValue[] seqTmp = basicOCSPResponse.getSequence(2); + if (seqTmp.length < 3) { + throw new IOException("Unexpected BasicOCSPResponse value"); + } - DerValue[] seqTmp = basicOCSPResponse.getSequence(2); - DerValue responseData = seqTmp[0]; + DerValue responseData = seqTmp[0]; - // Need the DER encoded ResponseData to verify the signature later - byte[] responseDataDer = seqTmp[0].toByteArray(); + // Need the DER encoded ResponseData to verify the signature later + byte[] responseDataDer = seqTmp[0].toByteArray(); - // tbsResponseData - if (responseData.tag != DerValue.tag_Sequence) { - throw new IOException("Bad encoding in tbsResponseData " + - " element of OCSP response: expected ASN.1 SEQUENCE tag."); - } - DerInputStream seqDerIn = responseData.data; - DerValue seq = seqDerIn.getDerValue(); - - // version - if (seq.isContextSpecific((byte)0)) { - // seq[0] is version - if (seq.isConstructed() && seq.isContextSpecific()) { - //System.out.println ("version is available"); - seq = seq.data.getDerValue(); - version = seq.getInteger(); - if (seq.data.available() != 0) { - throw new IOException("Bad encoding in version " + - " element of OCSP response: bad format"); - } - seq = seqDerIn.getDerValue(); + // tbsResponseData + if (responseData.tag != DerValue.tag_Sequence) { + throw new IOException("Bad encoding in tbsResponseData " + + "element of OCSP response: expected ASN.1 SEQUENCE tag."); + } + DerInputStream seqDerIn = responseData.data; + DerValue seq = seqDerIn.getDerValue(); + + // version + if (seq.isContextSpecific((byte)0)) { + // seq[0] is version + if (seq.isConstructed() && seq.isContextSpecific()) { + //System.out.println ("version is available"); + seq = seq.data.getDerValue(); + int version = seq.getInteger(); + if (seq.data.available() != 0) { + throw new IOException("Bad encoding in version " + + " element of OCSP response: bad format"); } + seq = seqDerIn.getDerValue(); } + } - // responderID - short tag = (byte)(seq.tag & 0x1f); - if (tag == NAME_TAG) { - responderName = new CertificateIssuerName(seq.getData()); - if (DEBUG != null) { - DEBUG.println("OCSP Responder name: " + responderName); - } - } else if (tag == KEY_TAG) { - // Ignore, for now - } else { - throw new IOException("Bad encoding in responderID element " + - "of OCSP response: expected ASN.1 context specific tag 0 " + - "or 1"); + // responderID + short tag = (byte)(seq.tag & 0x1f); + if (tag == NAME_TAG) { + if (DEBUG != null) { + X500Name responderName = new X500Name(seq.getData()); + DEBUG.println("OCSP Responder name: " + responderName); } + } else if (tag == KEY_TAG) { + // Ignore, for now + } else { + throw new IOException("Bad encoding in responderID element of " + + "OCSP response: expected ASN.1 context specific tag 0 or 1"); + } - // producedAt - seq = seqDerIn.getDerValue(); - producedAtDate = seq.getGeneralizedTime(); + // producedAt + seq = seqDerIn.getDerValue(); + if (DEBUG != null) { + Date producedAtDate = seq.getGeneralizedTime(); + DEBUG.println("OCSP response produced at: " + producedAtDate); + } - // responses - DerValue[] singleResponseDer = seqDerIn.getSequence(1); - // Examine only the first response - singleResponse = new SingleResponse(singleResponseDer[0]); + // responses + DerValue[] singleResponseDer = seqDerIn.getSequence(1); + singleResponseMap + = new HashMap(singleResponseDer.length); + if (DEBUG != null) { + DEBUG.println("OCSP number of SingleResponses: " + + singleResponseDer.length); + } + for (int i = 0; i < singleResponseDer.length; i++) { + SingleResponse singleResponse + = new SingleResponse(singleResponseDer[i]); + singleResponseMap.put(singleResponse.getCertId(), singleResponse); + } - // responseExtensions - if (seqDerIn.available() > 0) { - seq = seqDerIn.getDerValue(); - if (seq.isContextSpecific((byte)1)) { - DerValue[] responseExtDer = seq.data.getSequence(3); - Extension[] responseExtension = - new Extension[responseExtDer.length]; - for (int i = 0; i < responseExtDer.length; i++) { - responseExtension[i] = new Extension(responseExtDer[i]); - if (DEBUG != null) { - DEBUG.println("OCSP extension: " + - responseExtension[i]); - } - if ((responseExtension[i].getExtensionId()).equals( - OCSP_NONCE_EXTENSION_OID)) { - ocspNonce = - responseExtension[i].getExtensionValue(); - - } else if (responseExtension[i].isCritical()) { - throw new IOException( - "Unsupported OCSP critical extension: " + - responseExtension[i].getExtensionId()); - } + // responseExtensions + if (seqDerIn.available() > 0) { + seq = seqDerIn.getDerValue(); + if (seq.isContextSpecific((byte)1)) { + DerValue[] responseExtDer = seq.data.getSequence(3); + for (int i = 0; i < responseExtDer.length; i++) { + Extension responseExtension + = new Extension(responseExtDer[i]); + if (DEBUG != null) { + DEBUG.println("OCSP extension: " + responseExtension); + } + if (responseExtension.getExtensionId().equals( + OCSP_NONCE_EXTENSION_OID)) { + /* + ocspNonce = + responseExtension[i].getExtensionValue(); + */ + } else if (responseExtension.isCritical()) { + throw new IOException( + "Unsupported OCSP critical extension: " + + responseExtension.getExtensionId()); } } } + } - // signatureAlgorithmId - sigAlgId = AlgorithmId.parse(seqTmp[1]); + // signatureAlgorithmId + AlgorithmId sigAlgId = AlgorithmId.parse(seqTmp[1]); - // signature - byte[] signature = seqTmp[2].getBitString(); - X509CertImpl[] x509Certs = null; + // signature + byte[] signature = seqTmp[2].getBitString(); + X509CertImpl[] x509Certs = null; - // if seq[3] is available , then it is a sequence of certificates - if (seqTmp.length > 3) { - // certs are available - DerValue seqCert = seqTmp[3]; - if (! seqCert.isContextSpecific((byte)0)) { - throw new IOException("Bad encoding in certs element " + - "of OCSP response: expected ASN.1 context specific tag 0."); - } - DerValue[] certs = (seqCert.getData()).getSequence(3); - x509Certs = new X509CertImpl[certs.length]; + // if seq[3] is available , then it is a sequence of certificates + if (seqTmp.length > 3) { + // certs are available + DerValue seqCert = seqTmp[3]; + if (!seqCert.isContextSpecific((byte)0)) { + throw new IOException("Bad encoding in certs element of " + + "OCSP response: expected ASN.1 context specific tag 0."); + } + DerValue[] certs = seqCert.getData().getSequence(3); + x509Certs = new X509CertImpl[certs.length]; + try { for (int i = 0; i < certs.length; i++) { x509Certs[i] = new X509CertImpl(certs[i].toByteArray()); } + } catch (CertificateException ce) { + throw new IOException("Bad encoding in X509 Certificate", ce); } + } - // Check whether the cert returned by the responder is trusted - if (x509Certs != null && x509Certs[0] != null) { - X509CertImpl cert = x509Certs[0]; + // Check whether the cert returned by the responder is trusted + if (x509Certs != null && x509Certs[0] != null) { + X509CertImpl cert = x509Certs[0]; - // First check if the cert matches the responder cert which - // was set locally. - if (cert.equals(responderCert)) { - // cert is trusted, now verify the signed response + // First check if the cert matches the responder cert which + // was set locally. + if (cert.equals(responderCert)) { + // cert is trusted, now verify the signed response - // Next check if the cert was issued by the responder cert - // which was set locally. - } else if (cert.getIssuerX500Principal().equals( - responderCert.getSubjectX500Principal())) { + // Next check if the cert was issued by the responder cert + // which was set locally. + } else if (cert.getIssuerX500Principal().equals( + responderCert.getSubjectX500Principal())) { - // Check for the OCSPSigning key purpose + // Check for the OCSPSigning key purpose + try { List keyPurposes = cert.getExtendedKeyUsage(); if (keyPurposes == null || !keyPurposes.contains(KP_OCSP_SIGNING_OID)) { - if (DEBUG != null) { - DEBUG.println("Responder's certificate is not " + - "valid for signing OCSP responses."); - } throw new CertPathValidatorException( "Responder's certificate not valid for signing " + "OCSP responses"); } + } catch (CertificateParsingException cpe) { + // assume cert is not valid for signing + throw new CertPathValidatorException( + "Responder's certificate not valid for signing " + + "OCSP responses", cpe); + } - // check the validity - try { - Date dateCheckedAgainst = params.getDate(); - if (dateCheckedAgainst == null) { - cert.checkValidity(); - } else { - cert.checkValidity(dateCheckedAgainst); - } - } catch (GeneralSecurityException e) { - if (DEBUG != null) { - DEBUG.println("Responder's certificate is not " + - "within the validity period."); - } - throw new CertPathValidatorException( - "Responder's certificate not within the " + - "validity period"); - } - - // check for revocation - // - // A CA may specify that an OCSP client can trust a - // responder for the lifetime of the responder's - // certificate. The CA does so by including the - // extension id-pkix-ocsp-nocheck. - // - Extension noCheck = - cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); - if (noCheck != null) { - if (DEBUG != null) { - DEBUG.println("Responder's certificate includes " + - "the extension id-pkix-ocsp-nocheck."); - } + // check the validity + try { + if (dateCheckedAgainst == null) { + cert.checkValidity(); } else { - // we should do the revocating checking of the - // authorized responder in a future update. + cert.checkValidity(dateCheckedAgainst); } + } catch (GeneralSecurityException e) { + throw new CertPathValidatorException( + "Responder's certificate not within the " + + "validity period", e); + } - // verify the signature - try { - cert.verify(responderCert.getPublicKey()); - responderCert = cert; - // cert is trusted, now verify the signed response - - } catch (GeneralSecurityException e) { - responderCert = null; - } - } else { + // check for revocation + // + // A CA may specify that an OCSP client can trust a + // responder for the lifetime of the responder's + // certificate. The CA does so by including the + // extension id-pkix-ocsp-nocheck. + // + Extension noCheck = + cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); + if (noCheck != null) { if (DEBUG != null) { - DEBUG.println("Responder's certificate is not " + - "authorized to sign OCSP responses."); + DEBUG.println("Responder's certificate includes " + + "the extension id-pkix-ocsp-nocheck."); } - throw new CertPathValidatorException( - "Responder's certificate not authorized to sign " + - "OCSP responses"); + } else { + // we should do the revocation checking of the + // authorized responder in a future update. } - } - // Confirm that the signed response was generated using the public - // key from the trusted responder cert - if (responderCert != null) { + // verify the signature + try { + cert.verify(responderCert.getPublicKey()); + responderCert = cert; + // cert is trusted, now verify the signed response - if (! verifyResponse(responseDataDer, responderCert, - sigAlgId, signature, params)) { - if (DEBUG != null) { - DEBUG.println("Error verifying OCSP Responder's " + - "signature"); - } - throw new CertPathValidatorException( - "Error verifying OCSP Responder's signature"); + } catch (GeneralSecurityException e) { + responderCert = null; } } else { - // Need responder's cert in order to verify the signature - if (DEBUG != null) { - DEBUG.println("Unable to verify OCSP Responder's " + - "signature"); - } throw new CertPathValidatorException( - "Unable to verify OCSP Responder's signature"); + "Responder's certificate is not authorized to sign " + + "OCSP responses"); } - } catch (CertPathValidatorException cpve) { - throw cpve; - } catch (Exception e) { - throw new CertPathValidatorException(e); } + + // Confirm that the signed response was generated using the public + // key from the trusted responder cert + if (responderCert != null) { + if (!verifyResponse(responseDataDer, responderCert, + sigAlgId, signature)) { + throw new CertPathValidatorException( + "Error verifying OCSP Responder's signature"); + } + } else { + // Need responder's cert in order to verify the signature + throw new CertPathValidatorException( + "Unable to verify OCSP Responder's signature"); + } + } + + /** + * Returns the OCSP ResponseStatus. + */ + ResponseStatus getResponseStatus() { + return responseStatus; } /* @@ -449,11 +446,10 @@ class OCSPResponse { * The responder's cert is implicitly trusted. */ private boolean verifyResponse(byte[] responseData, X509Certificate cert, - AlgorithmId sigAlgId, byte[] signBytes, PKIXParameters params) - throws SignatureException { + AlgorithmId sigAlgId, byte[] signBytes) + throws CertPathValidatorException { try { - Signature respSignature = Signature.getInstance(sigAlgId.getName()); respSignature.initVerify(cert); respSignature.update(responseData); @@ -472,92 +468,33 @@ class OCSPResponse { return false; } } catch (InvalidKeyException ike) { - throw new SignatureException(ike); - + throw new CertPathValidatorException(ike); } catch (NoSuchAlgorithmException nsae) { - throw new SignatureException(nsae); + throw new CertPathValidatorException(nsae); + } catch (SignatureException se) { + throw new CertPathValidatorException(se); } } - /* - * Return the revocation status code for a given certificate. + /** + * Returns the SingleResponse of the specified CertId, or null if + * there is no response for that CertId. */ - // used by OCSPChecker - int getCertStatus(SerialNumber sn) { - // ignore serial number for now; if we support multiple - // requests/responses then it will be used - return singleResponse.getStatus(); - } - - // used by OCSPChecker - CertId getCertId() { - return singleResponse.getCertId(); - } - - Date getRevocationTime() { - return singleResponse.getRevocationTime(); - } - - CRLReason getRevocationReason() { - return singleResponse.getRevocationReason(); - } - - Map getSingleExtensions() { - return singleResponse.getSingleExtensions(); - } - - /* - * Map an OCSP response status code to a string. - */ - static private String responseToText(int status) { - switch (status) { - case 0: - return "Successful"; - case 1: - return "Malformed request"; - case 2: - return "Internal error"; - case 3: - return "Try again later"; - case 4: - return "Unused status code"; - case 5: - return "Request must be signed"; - case 6: - return "Request is unauthorized"; - default: - return ("Unknown status code: " + status); - } - } - - /* - * Map a certificate's revocation status code to a string. - */ - // used by OCSPChecker - static String certStatusToText(int certStatus) { - switch (certStatus) { - case 0: - return "Good"; - case 1: - return "Revoked"; - case 2: - return "Unknown"; - default: - return ("Unknown certificate status code: " + certStatus); - } + SingleResponse getSingleResponse(CertId certId) { + return singleResponseMap.get(certId); } /* * A class representing a single OCSP response. */ - private class SingleResponse { - private CertId certId; - private int certStatus; - private Date thisUpdate; - private Date nextUpdate; - private Date revocationTime; - private CRLReason revocationReason = CRLReason.UNSPECIFIED; - private HashMap singleExtensions; + final static class SingleResponse implements OCSP.RevocationStatus { + private final CertId certId; + private final CertStatus certStatus; + private final Date thisUpdate; + private final Date nextUpdate; + private final Date revocationTime; + private final CRLReason revocationReason; + private final Map singleExtensions; private SingleResponse(DerValue der) throws IOException { if (der.tag != DerValue.tag_Sequence) { @@ -568,35 +505,48 @@ class OCSPResponse { certId = new CertId(tmp.getDerValue().data); DerValue derVal = tmp.getDerValue(); short tag = (byte)(derVal.tag & 0x1f); - if (tag == CERT_STATUS_GOOD) { - certStatus = CERT_STATUS_GOOD; - } else if (tag == CERT_STATUS_REVOKED) { - certStatus = CERT_STATUS_REVOKED; + if (tag == CERT_STATUS_REVOKED) { + certStatus = CertStatus.REVOKED; revocationTime = derVal.data.getGeneralizedTime(); if (derVal.data.available() != 0) { - int reason = derVal.getEnumerated(); - // if reason out-of-range just leave as UNSPECIFIED - if (reason >= 0 && reason < values.length) { - revocationReason = values[reason]; + DerValue dv = derVal.data.getDerValue(); + tag = (byte)(dv.tag & 0x1f); + if (tag == 0) { + int reason = dv.data.getEnumerated(); + // if reason out-of-range just leave as UNSPECIFIED + if (reason >= 0 && reason < values.length) { + revocationReason = values[reason]; + } else { + revocationReason = CRLReason.UNSPECIFIED; + } + } else { + revocationReason = CRLReason.UNSPECIFIED; } + } else { + revocationReason = CRLReason.UNSPECIFIED; } // RevokedInfo if (DEBUG != null) { DEBUG.println("Revocation time: " + revocationTime); DEBUG.println("Revocation reason: " + revocationReason); } - - } else if (tag == CERT_STATUS_UNKNOWN) { - certStatus = CERT_STATUS_UNKNOWN; - } else { - throw new IOException("Invalid certificate status"); + revocationTime = null; + revocationReason = CRLReason.UNSPECIFIED; + if (tag == CERT_STATUS_GOOD) { + certStatus = CertStatus.GOOD; + } else if (tag == CERT_STATUS_UNKNOWN) { + certStatus = CertStatus.UNKNOWN; + } else { + throw new IOException("Invalid certificate status"); + } } thisUpdate = tmp.getGeneralizedTime(); if (tmp.available() == 0) { // we are done + nextUpdate = null; } else { derVal = tmp.getDerValue(); tag = (byte)(derVal.tag & 0x1f); @@ -610,6 +560,8 @@ class OCSPResponse { derVal = tmp.getDerValue(); tag = (byte)(derVal.tag & 0x1f); } + } else { + nextUpdate = null; } } // singleExtensions @@ -627,7 +579,11 @@ class OCSPResponse { DEBUG.println("OCSP single extension: " + ext); } } + } else { + singleExtensions = Collections.emptyMap(); } + } else { + singleExtensions = Collections.emptyMap(); } long now = System.currentTimeMillis(); @@ -657,7 +613,7 @@ class OCSPResponse { /* * Return the certificate's revocation status code */ - private int getStatus() { + @Override public CertStatus getCertStatus() { return certStatus; } @@ -665,28 +621,28 @@ class OCSPResponse { return certId; } - private Date getRevocationTime() { - return revocationTime; + @Override public Date getRevocationTime() { + return (Date) revocationTime.clone(); } - private CRLReason getRevocationReason() { + @Override public CRLReason getRevocationReason() { return revocationReason; } - private Map getSingleExtensions() { - return singleExtensions; + @Override + public Map getSingleExtensions() { + return Collections.unmodifiableMap(singleExtensions); } /** * Construct a string representation of a single OCSP response. */ - public String toString() { + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("SingleResponse: \n"); sb.append(certId); - sb.append("\nCertStatus: "+ certStatusToText(getCertStatus(null)) + - "\n"); - if (certStatus == CERT_STATUS_REVOKED) { + sb.append("\nCertStatus: "+ certStatus + "\n"); + if (certStatus == CertStatus.REVOKED) { sb.append("revocationTime is " + revocationTime + "\n"); sb.append("revocationReason is " + revocationReason + "\n"); } diff --git a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java index 63335d2342c03d4c25e712b27d0dff51546da1f0..145879239accaa2eb97c68565fe25ee503a3b2a4 100644 --- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java +++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 @@ -28,8 +28,6 @@ package sun.security.provider.certpath; import java.io.IOException; import java.security.AccessController; import java.security.InvalidAlgorithmParameterException; -import java.security.PrivilegedAction; -import java.security.Security; import java.security.cert.CertPath; import java.security.cert.CertPathParameters; import java.security.cert.CertPathValidatorException; @@ -49,6 +47,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.Set; import javax.security.auth.x500.X500Principal; +import sun.security.action.GetBooleanSecurityPropertyAction; import sun.security.util.Debug; /** @@ -67,7 +66,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { private List userCheckers; private String sigProvider; private BasicChecker basicChecker; - private String ocspProperty; + private boolean ocspEnabled = false; + private boolean onlyEECert = false; /** * Default constructor. @@ -253,13 +253,12 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { if (pkixParam.isRevocationEnabled()) { // Examine OCSP security property - ocspProperty = AccessController.doPrivileged( - new PrivilegedAction() { - public String run() { - return - Security.getProperty(OCSPChecker.OCSP_ENABLE_PROP); - } - }); + ocspEnabled = AccessController.doPrivileged( + new GetBooleanSecurityPropertyAction + (OCSPChecker.OCSP_ENABLE_PROP)); + onlyEECert = AccessController.doPrivileged( + new GetBooleanSecurityPropertyAction + ("com.sun.security.onlyCheckRevocationOfEECert")); } } @@ -301,15 +300,15 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { if (pkixParam.isRevocationEnabled()) { // Use OCSP if it has been enabled - if ("true".equalsIgnoreCase(ocspProperty)) { + if (ocspEnabled) { OCSPChecker ocspChecker = - new OCSPChecker(cpOriginal, pkixParam); + new OCSPChecker(cpOriginal, pkixParam, onlyEECert); certPathCheckers.add(ocspChecker); } // Always use CRLs - CrlRevocationChecker revocationChecker = - new CrlRevocationChecker(anchor, pkixParam, certList); + CrlRevocationChecker revocationChecker = new + CrlRevocationChecker(anchor, pkixParam, certList, onlyEECert); certPathCheckers.add(revocationChecker); } diff --git a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java index 0c439349d3cf47d1322105adb0f9709814688ed1..6723cb8c6b896d06692297cc2887e1089b4a08b1 100644 --- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java +++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 @@ -26,6 +26,7 @@ package sun.security.provider.certpath; import java.io.IOException; +import java.security.AccessController; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.Principal; @@ -44,6 +45,7 @@ import java.util.LinkedList; import java.util.Set; import javax.security.auth.x500.X500Principal; +import sun.security.action.GetBooleanSecurityPropertyAction; import sun.security.x509.X500Name; import sun.security.x509.PKIXExtensions; import sun.security.util.Debug; @@ -85,6 +87,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { private PublicKey finalPublicKey; private X509CertSelector targetSel; private List orderedCertStores; + private boolean onlyEECert = false; /** * Create an instance of SunCertPathBuilder. @@ -97,6 +100,9 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { } catch (CertificateException e) { throw new CertPathBuilderException(e); } + onlyEECert = AccessController.doPrivileged( + new GetBooleanSecurityPropertyAction + ("com.sun.security.onlyCheckRevocationOfEECert")); } /** @@ -256,7 +262,6 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { /* * Private build reverse method. - * */ private void buildReverse(List> adjacencyList, LinkedList certPathList) throws Exception @@ -296,7 +301,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { currentState.updateState(anchor); // init the crl checker currentState.crlChecker = - new CrlRevocationChecker(null, buildParams); + new CrlRevocationChecker(null, buildParams, null, onlyEECert); try { depthFirstSearchReverse(null, currentState, new ReverseBuilder(buildParams, targetSubjectDN), adjacencyList, @@ -341,10 +346,12 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { adjacencyList.add(new LinkedList()); // init the crl checker - currentState.crlChecker = new CrlRevocationChecker(null, buildParams); + currentState.crlChecker + = new CrlRevocationChecker(null, buildParams, null, onlyEECert); depthFirstSearchForward(targetSubjectDN, currentState, - new ForwardBuilder(buildParams, targetSubjectDN, searchAllCertStores), + new ForwardBuilder + (buildParams, targetSubjectDN, searchAllCertStores, onlyEECert), adjacencyList, certPathList); } @@ -486,8 +493,8 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { userCheckers.add(mustCheck, basicChecker); mustCheck++; if (buildParams.isRevocationEnabled()) { - userCheckers.add(mustCheck, - new CrlRevocationChecker(anchor, buildParams)); + userCheckers.add(mustCheck, new CrlRevocationChecker + (anchor, buildParams, null, onlyEECert)); mustCheck++; } } diff --git a/src/share/classes/sun/security/x509/AccessDescription.java b/src/share/classes/sun/security/x509/AccessDescription.java index 1544ea953bec5864f786be79daf0459cd7614995..0911018110fe23a243a6e4b067c9bc4899c1848e 100644 --- a/src/share/classes/sun/security/x509/AccessDescription.java +++ b/src/share/classes/sun/security/x509/AccessDescription.java @@ -113,7 +113,7 @@ public final class AccessDescription { } else { method = accessMethod.toString(); } - return ("accessMethod: " + method + + return ("\n accessMethod: " + method + "\n accessLocation: " + accessLocation.toString() + "\n"); } } diff --git a/src/share/demo/jvmti/waiters/Agent.cpp b/src/share/demo/jvmti/waiters/Agent.cpp index 30786133d50236e7de6c4171b453d6891786a23d..f4da70281fd75e817ad38fd939b8dcbf379fc0e3 100644 --- a/src/share/demo/jvmti/waiters/Agent.cpp +++ b/src/share/demo/jvmti/waiters/Agent.cpp @@ -72,36 +72,30 @@ Agent::get_monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object) { jvmtiError err; Monitor *m; + jlong tag; - /* We use tags to track these, the tag is the Monitor pointer */ - err = jvmti->RawMonitorEnter(lock); { - check_jvmti_error(jvmti, err, "raw monitor enter"); - - /* The raw monitor enter/exit protects us from creating two - * instances for the same object. - */ - jlong tag; - - m = NULL; - tag = (jlong)0; - err = jvmti->GetTag(object, &tag); - check_jvmti_error(jvmti, err, "get tag"); - /*LINTED*/ - m = (Monitor *)(void *)(ptrdiff_t)tag; - if ( m == NULL ) { - m = new Monitor(jvmti, env, object); - /*LINTED*/ - tag = (jlong)(ptrdiff_t)(void *)m; - err = jvmti->SetTag(object, tag); - check_jvmti_error(jvmti, err, "set tag"); - /* Save monitor on list */ + m = NULL; + tag = (jlong)0; + err = jvmti->GetTag(object, &tag); + check_jvmti_error(jvmti, err, "get tag"); + /*LINTED*/ + m = (Monitor *)(void *)(ptrdiff_t)tag; + if ( m == NULL ) { + m = new Monitor(jvmti, env, object); + /* Save monitor on list */ + if (monitor_count == monitor_list_size) { + monitor_list_size += monitor_list_grow_size; monitor_list = (Monitor**)realloc((void*)monitor_list, - (monitor_count+1)*(int)sizeof(Monitor*)); - monitor_list[monitor_count++] = m; + (monitor_list_size)*(int)sizeof(Monitor*)); } - } err = jvmti->RawMonitorExit(lock); - check_jvmti_error(jvmti, err, "raw monitor exit"); - + monitor_list[monitor_count] = m; + m->set_slot(monitor_count); + monitor_count++; + /*LINTED*/ + tag = (jlong)(ptrdiff_t)(void *)m; + err = jvmti->SetTag(object, tag); + check_jvmti_error(jvmti, err, "set tag"); + } return m; } @@ -112,12 +106,11 @@ Agent::Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) stdout_message("Agent created..\n"); stdout_message("VMInit...\n"); - /* Create a Monitor lock to use */ - err = jvmti->CreateRawMonitor("waiters Agent lock", &lock); - check_jvmti_error(jvmti, err, "create raw monitor"); /* Start monitor list */ monitor_count = 0; - monitor_list = (Monitor**)malloc((int)sizeof(Monitor*)); + monitor_list_size = initial_monitor_list_size; + monitor_list = (Monitor**) + malloc(monitor_list_size*(int)sizeof(Monitor*)); } Agent::~Agent() @@ -134,9 +127,6 @@ void Agent::vm_death(jvmtiEnv *jvmti, JNIEnv *env) delete monitor_list[i]; } free(monitor_list); - /* Destroy the Monitor lock to use */ - err = jvmti->DestroyRawMonitor(lock); - check_jvmti_error(jvmti, err, "destroy raw monitor"); /* Print death message */ stdout_message("VMDeath...\n"); } @@ -215,8 +205,16 @@ void Agent::object_free(jvmtiEnv* jvmti, jlong tag) /* We just cast the tag to a C++ pointer and delete it. * we know it can only be a Monitor *. */ - Monitor *m; + Monitor *m; /*LINTED*/ m = (Monitor *)(ptrdiff_t)tag; + if (monitor_count > 1) { + /* Move the last element to this Monitor's slot */ + int slot = m->get_slot(); + Monitor *last = monitor_list[monitor_count-1]; + monitor_list[slot] = last; + last->set_slot(slot); + } + monitor_count--; delete m; } diff --git a/src/share/demo/jvmti/waiters/Agent.hpp b/src/share/demo/jvmti/waiters/Agent.hpp index 9885baf8ba35a6d4749139bd7c8236abd3d2a811..65fe1227362500f7b82d0703b3062ff24584510c 100644 --- a/src/share/demo/jvmti/waiters/Agent.hpp +++ b/src/share/demo/jvmti/waiters/Agent.hpp @@ -34,8 +34,12 @@ class Agent { private: - jrawMonitorID lock; + enum { + initial_monitor_list_size = 64, + monitor_list_grow_size = 16 + }; Monitor **monitor_list; + unsigned monitor_list_size; unsigned monitor_count; Thread *get_thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread); Monitor *get_monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object); diff --git a/src/share/demo/jvmti/waiters/Monitor.cpp b/src/share/demo/jvmti/waiters/Monitor.cpp index a5efc5b23b30b660b7b7b3d4d58bbec9ad14e902..acd092a142af03341c283d965ba1416e94ad2978 100644 --- a/src/share/demo/jvmti/waiters/Monitor.cpp +++ b/src/share/demo/jvmti/waiters/Monitor.cpp @@ -73,6 +73,16 @@ Monitor::~Monitor() name, contends, waits, timeouts); } +int Monitor::get_slot() +{ + return slot; +} + +void Monitor::set_slot(int aslot) +{ + slot = aslot; +} + void Monitor::contended() { contends++; diff --git a/src/share/demo/jvmti/waiters/Monitor.hpp b/src/share/demo/jvmti/waiters/Monitor.hpp index 95b49560abdc23d12365512adc681aef0e40fca3..af6dedda5b9f65ee4f519fd1685e6296ff879dd8 100644 --- a/src/share/demo/jvmti/waiters/Monitor.hpp +++ b/src/share/demo/jvmti/waiters/Monitor.hpp @@ -35,6 +35,7 @@ class Monitor { private: char name[64]; + int slot; unsigned contends; unsigned waits; unsigned timeouts; @@ -42,6 +43,8 @@ class Monitor { public: Monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object); ~Monitor(); + int get_slot(); + void set_slot(int i); void contended(); void waited(); void timeout(); diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h index df8f27e6602eaf6d68f43018fcb3b15ce653fe6e..4f141d21fb8dc0202e4aed41c94cc677d293fd19 100644 --- a/src/share/javavm/export/jvm.h +++ b/src/share/javavm/export/jvm.h @@ -374,6 +374,12 @@ JVM_FindPrimitiveClass(JNIEnv *env, const char *utf); JNIEXPORT void JNICALL JVM_ResolveClass(JNIEnv *env, jclass cls); +/* + * Find a class from a boot class loader. Returns NULL if class not found. + */ +JNIEXPORT jclass JNICALL +JVM_FindClassFromBootLoader(JNIEnv *env, const char *name); + /* * Find a class from a given class loader. Throw ClassNotFoundException * or NoClassDefFoundError depending on the value of the last diff --git a/src/share/lib/net.properties b/src/share/lib/net.properties index e941d50e3f49fdaf5e26359c07695c0d3cc11a42..da78a84d511d3a137736d6f0438c3c1892515b38 100644 --- a/src/share/lib/net.properties +++ b/src/share/lib/net.properties @@ -32,7 +32,7 @@ java.net.useSystemProxies=false # # http.proxyHost= # http.proxyPort=80 -# http.nonProxyHosts=localhost|127.0.0.1 +http.nonProxyHosts=localhost|127.*|[::1] # # HTTPS Proxy Settings. proxyHost is the name of the proxy server # (e.g. proxy.mydomain.com), proxyPort is the port number to use (default @@ -49,7 +49,7 @@ java.net.useSystemProxies=false # # ftp.proxyHost= # ftp.proxyPort=80 -# ftp.nonProxyHosts=localhost|127.0.0.1 +ftp.nonProxyHosts=localhost|127.*|[::1] # # Gopher Proxy settings. proxyHost is the name of the proxy server # (e.g. proxy.mydomain.com), proxyPort is the port number to use (default diff --git a/src/share/native/java/lang/ClassLoader.c b/src/share/native/java/lang/ClassLoader.c index bedf87ce7e6571ad4fa3cce43edf456ff4581d6b..b080fef2e53be7b744e7b01a9801301e24a31c4e 100644 --- a/src/share/native/java/lang/ClassLoader.c +++ b/src/share/native/java/lang/ClassLoader.c @@ -237,6 +237,9 @@ Java_java_lang_ClassLoader_resolveClass0(JNIEnv *env, jobject this, JVM_ResolveClass(env, cls); } +/* + * Returns NULL if class not found. + */ JNIEXPORT jclass JNICALL Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, jstring classname) @@ -246,7 +249,6 @@ Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, char buf[128]; if (classname == NULL) { - JNU_ThrowClassNotFoundException(env, 0); return 0; } @@ -258,11 +260,10 @@ Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, VerifyFixClassname(clname); if (!VerifyClassname(clname, JNI_TRUE)) { /* expects slashed name */ - JNU_ThrowClassNotFoundException(env, clname); goto done; } - cls = JVM_FindClassFromClassLoader(env, clname, JNI_FALSE, 0, JNI_FALSE); + cls = JVM_FindClassFromBootLoader(env, clname); done: if (clname != buf) { diff --git a/src/solaris/bin/java_md.c b/src/solaris/bin/java_md.c index 2e574ec2cec5d4638486054fc006dba71d71e7a0..73efc1090fddb70c1e82ef639f8bcf9cef8ebe76 100644 --- a/src/solaris/bin/java_md.c +++ b/src/solaris/bin/java_md.c @@ -1324,12 +1324,12 @@ FindBootStrapClass(JNIEnv *env, const char* classname) { if (findBootClass == NULL) { findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT, - "JVM_FindClassFromClassLoader"); + "JVM_FindClassFromBootLoader"); if (findBootClass == NULL) { JLI_ReportErrorMessage(DLL_ERROR4, - "JVM_FindClassFromClassLoader"); + "JVM_FindClassFromBootLoader"); return NULL; } } - return findBootClass(env, classname, JNI_FALSE, (jobject)NULL, JNI_FALSE); + return findBootClass(env, classname); } diff --git a/src/windows/bin/java_md.c b/src/windows/bin/java_md.c index df5e6988c5e592ea84d83259b0e491f6fa4bb29d..a4fa4ccd63a122dbd85ce15b9c063c573a6e31ec 100644 --- a/src/windows/bin/java_md.c +++ b/src/windows/bin/java_md.c @@ -1093,12 +1093,6 @@ void SetJavaLauncherPlatformProps() {} */ static FindClassFromBootLoader_t *findBootClass = NULL; -#ifdef _M_AMD64 -#define JVM_BCLOADER "JVM_FindClassFromClassLoader" -#else -#define JVM_BCLOADER "_JVM_FindClassFromClassLoader@20" -#endif /* _M_AMD64 */ - jclass FindBootStrapClass(JNIEnv *env, const char *classname) { HMODULE hJvm; @@ -1108,13 +1102,13 @@ jclass FindBootStrapClass(JNIEnv *env, const char *classname) if (hJvm == NULL) return NULL; /* need to use the demangled entry point */ findBootClass = (FindClassFromBootLoader_t *)GetProcAddress(hJvm, - JVM_BCLOADER); + "JVM_FindClassFromBootLoader"); if (findBootClass == NULL) { - JLI_ReportErrorMessage(DLL_ERROR4, JVM_BCLOADER); + JLI_ReportErrorMessage(DLL_ERROR4, "JVM_FindClassFromBootLoader"); return NULL; } } - return findBootClass(env, classname, JNI_FALSE, (jobject)NULL, JNI_FALSE); + return findBootClass(env, classname); } void diff --git a/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java b/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java index a4334b42f12b9e7fc310ea121356116a94a50899..788a4d0ff21d6e99cd9150510f3baf39cec6cb5e 100644 --- a/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java +++ b/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java @@ -67,6 +67,9 @@ public class D3DGraphicsDevice extends Win32GraphicsDevice { if (d3dAvailable) { // we don't use pixel formats for the d3d pipeline pfDisabled = true; + sun.misc.PerfCounter.getD3DAvailable().set(1); + } else { + sun.misc.PerfCounter.getD3DAvailable().set(0); } } diff --git a/test/com/sun/jdi/BreakpointWithFullGC.sh b/test/com/sun/jdi/BreakpointWithFullGC.sh new file mode 100644 index 0000000000000000000000000000000000000000..74106760c7935e109c8dafabdc13b174cb240cde --- /dev/null +++ b/test/com/sun/jdi/BreakpointWithFullGC.sh @@ -0,0 +1,128 @@ +#!/bin/sh + +# +# Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6862295 +# @summary Verify breakpoints still work after a full GC. +# @author dcubed (based on the test program posted to the following +# Eclipse thread https://bugs.eclipse.org/bugs/show_bug.cgi?id=279137) +# +# @run shell BreakpointWithFullGC.sh + +compileOptions=-g +# Hijacking the mode parameter to make sure we use a small amount +# of memory and can see what GC is doing. +mode="-Xmx32m -verbose:gc" +# Force use of a GC framework collector to see the original failure. +#mode="$mode -XX:+UseSerialGC" + +# Uncomment this to see the JDI trace +#jdbOptions=-dbgtrace + +createJavaFile() +{ + cat < $1.java.1 + +import java.util.ArrayList; +import java.util.List; + +public class $1 { + public static List objList = new ArrayList(); + + private static void init(int numObjs) { + for (int i = 0; i < numObjs; i++) { + objList.add(new Object()); + } + } + + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + System.out.println("top of loop"); // @1 breakpoint + init(1000000); + objList.clear(); + System.out.println("bottom of loop"); // @1 breakpoint + } + System.out.println("end of test"); // @1 breakpoint + } +} + +EOF +} + +# This is called to feed cmds to jdb. +dojdbCmds() +{ + setBkpts @1 + + # get to the first loop breakpoint + runToBkpt + # 19 "cont" commands gets us through all the loop breakpoints. + # Use for-loop instead of while-loop to avoid creating processes + # for '[' and 'expr'. + for ii in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; do + contToBkpt + done + # get to the last breakpoint + contToBkpt +} + + +mysetup() +{ + if [ -z "$TESTSRC" ] ; then + TESTSRC=. + fi + + for ii in . $TESTSRC $TESTSRC/.. ; do + if [ -r "$ii/ShellScaffold.sh" ] ; then + . $ii/ShellScaffold.sh + break + fi + done +} + +# You could replace this next line with the contents +# of ShellScaffold.sh and this script will run just the same. +mysetup + +runit + +# make sure we hit the first breakpoint at least once +jdbFailIfNotPresent 'System\..*top of loop' + +# make sure we hit the second breakpoint at least once +jdbFailIfNotPresent 'System\..*bottom of loop' + +# make sure we hit the last breakpoint +jdbFailIfNotPresent 'System\..*end of test' + +# make sure we had at least one full GC +debuggeeFailIfNotPresent 'Full GC' + +# check for error message due to thread ID change +debuggeeFailIfPresent \ + 'Exception in thread "event-handler" java.lang.NullPointerException' + +pass diff --git a/test/java/lang/ProcessBuilder/Basic.java b/test/java/lang/ProcessBuilder/Basic.java index 745fab468b9d4376a2b5362422900c8a025e089a..afb8ea8210e92b7bb8d6d26f3675ea5ee7a18528 100644 --- a/test/java/lang/ProcessBuilder/Basic.java +++ b/test/java/lang/ProcessBuilder/Basic.java @@ -25,7 +25,7 @@ * @test * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689 * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313 - * 6464154 6523983 6206031 4960438 6631352 6631966 + * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958 * @summary Basic tests for Process and Environment Variable code * @run main/othervm Basic * @author Martin Buchholz @@ -302,6 +302,14 @@ public class Basic { printUTF8(val == null ? "null" : val); } else if (action.equals("System.getenv()")) { printUTF8(getenvAsString(System.getenv())); + } else if (action.equals("ArrayOOME")) { + Object dummy; + switch(new Random().nextInt(3)) { + case 0: dummy = new Integer[Integer.MAX_VALUE]; break; + case 1: dummy = new double[Integer.MAX_VALUE]; break; + case 2: dummy = new byte[Integer.MAX_VALUE][]; break; + default: throw new InternalError(); + } } else if (action.equals("pwd")) { printUTF8(new File(System.getProperty("user.dir")) .getCanonicalPath()); @@ -1472,6 +1480,22 @@ public class Basic { } } catch (Throwable t) { unexpected(t); } + //---------------------------------------------------------------- + // OOME in child allocating maximally sized array + // Test for hotspot/jvmti bug 6850957 + //---------------------------------------------------------------- + try { + List list = new ArrayList(javaChildArgs); + list.add(1, String.format("-XX:OnOutOfMemoryError=%s -version", + javaExe)); + list.add("ArrayOOME"); + ProcessResults r = run(new ProcessBuilder(list)); + check(r.out().contains("java.lang.OutOfMemoryError:")); + check(r.out().contains(javaExe)); + check(r.err().contains(System.getProperty("java.version"))); + equal(r.exitValue(), 1); + } catch (Throwable t) { unexpected(t); } + //---------------------------------------------------------------- // Windows has tricky semi-case-insensitive semantics //---------------------------------------------------------------- diff --git a/test/java/net/ProxySelector/B6737819.java b/test/java/net/ProxySelector/B6737819.java new file mode 100644 index 0000000000000000000000000000000000000000..360f1ae4aefe24e0d101ea283a6eeaefe09f5ecd --- /dev/null +++ b/test/java/net/ProxySelector/B6737819.java @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test + * @bug 6737819 + * @summary sun.misc.net.DefaultProxySelector doesn't use proxy setting to localhost + */ + +import java.net.ProxySelector; +import java.net.Proxy; +import java.net.URI; + +public class B6737819 { + private static String[] uris = { + "http://localhost/index.html", + "http://127.0.0.1/index.html", + "http://127.2/index.html", + "http://[::1]/index.html" + }; + public static void main(String[] args) throws Exception { + System.setProperty("http.proxyHost", "myproxy"); + System.setProperty("http.proxyPort", "8080"); + ProxySelector sel = ProxySelector.getDefault(); + java.util.List l; + // Default value for http.nonProxyHots should exclude all this uris + // from going through the HTTP proxy + for (String s : uris) { + l = sel.select(new URI(s)); + if (l.size() == 1 && l.get(0).type() != Proxy.Type.DIRECT) { + throw new RuntimeException("ProxySelector returned the wrong proxy for " + s); + } + } + // Let's override the default nonProxyHosts and make sure we now get a + // HTTP proxy + System.setProperty("http.nonProxyHosts", ""); + for (String s : uris) { + l = sel.select(new URI(s)); + if (l.size() == 1 && l.get(0).type() != Proxy.Type.HTTP) { + throw new RuntimeException("ProxySelector returned the wrong proxy for " + s); + } + } + } +} diff --git a/test/java/nio/file/Files/WalkWithSecurity.java b/test/java/nio/file/Files/WalkWithSecurity.java new file mode 100644 index 0000000000000000000000000000000000000000..5b2ab56447426f6ba81c3467fe45692540d24f20 --- /dev/null +++ b/test/java/nio/file/Files/WalkWithSecurity.java @@ -0,0 +1,132 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6876541 + * @summary Test Files.walkFileTree in the presence of a security manager + * @build WalkWithSecurity + * @run main/othervm WalkWithSecurity grantAll.policy pass + * @run main/othervm WalkWithSecurity denyAll.policy fail + * @run main/othervm WalkWithSecurity grantTopOnly.policy top_only + */ + +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.io.IOException; + +public class WalkWithSecurity { + + public static void main(String[] args) throws IOException { + String policyFile = args[0]; + ExpectedResult expectedResult = ExpectedResult.valueOf(args[1].toUpperCase()); + + String here = System.getProperty("user.dir"); + String testSrc = System.getProperty("test.src"); + if (testSrc == null) + throw new RuntimeException("This test must be run by jtreg"); + Path dir = Paths.get(testSrc); + + // Sanity check the environment + if (Paths.get(here).isSameFile(dir)) + throw new RuntimeException("Working directory cannot be " + dir); + DirectoryStream stream = dir.newDirectoryStream(); + try { + if (!stream.iterator().hasNext()) + throw new RuntimeException(testSrc + " is empty"); + } finally { + stream.close(); + } + + // Install security manager with the given policy file + System.setProperty("java.security.policy", + dir.resolve(policyFile).toString()); + System.setSecurityManager(new SecurityManager()); + + // Walk the source tree + CountingVisitor visitor = new CountingVisitor(); + SecurityException exception = null; + try { + Files.walkFileTree(dir, visitor); + } catch (SecurityException se) { + exception = se; + } + + // Check result + switch (expectedResult) { + case PASS: + if (exception != null) { + exception.printStackTrace(); + throw new RuntimeException("SecurityException not expected"); + } + if (visitor.count() == 0) + throw new RuntimeException("No files visited"); + break; + case FAIL: + if (exception == null) + throw new RuntimeException("SecurityException expected"); + if (visitor.count() > 0) + throw new RuntimeException("Files were visited"); + break; + case TOP_ONLY: + if (exception != null) { + exception.printStackTrace(); + throw new RuntimeException("SecurityException not expected"); + } + if (visitor.count() == 0) + throw new RuntimeException("Starting file not visited"); + if (visitor.count() > 1) + throw new RuntimeException("More than starting file visited"); + break; + default: + throw new RuntimeException("Should not get here"); + } + } + + static enum ExpectedResult { + PASS, + FAIL, + TOP_ONLY; + } + + static class CountingVisitor extends SimpleFileVisitor { + private int count; + + int count() { + return count; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir) { + System.out.println(dir); + count++; + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + System.out.println(file); + count++; + return FileVisitResult.CONTINUE; + } + } +} diff --git a/test/java/nio/file/Files/denyAll.policy b/test/java/nio/file/Files/denyAll.policy new file mode 100644 index 0000000000000000000000000000000000000000..32500947791001ea25267a6f5c54d95ec0075172 --- /dev/null +++ b/test/java/nio/file/Files/denyAll.policy @@ -0,0 +1,3 @@ +// policy file that does not grant any permissions +grant { +}; diff --git a/test/java/nio/file/Files/grantAll.policy b/test/java/nio/file/Files/grantAll.policy new file mode 100644 index 0000000000000000000000000000000000000000..85bc0d0fb51f23eea23c226cb8a1f7f79af92901 --- /dev/null +++ b/test/java/nio/file/Files/grantAll.policy @@ -0,0 +1,5 @@ +// policy file that grants read access to source directory and all descendants +grant { + permission java.io.FilePermission "${test.src}", "read"; + permission java.io.FilePermission "${test.src}${file.separator}-", "read"; +}; diff --git a/test/java/nio/file/Files/grantTopOnly.policy b/test/java/nio/file/Files/grantTopOnly.policy new file mode 100644 index 0000000000000000000000000000000000000000..fca1539416feb5a502dfacbff39fe0bc7e14a763 --- /dev/null +++ b/test/java/nio/file/Files/grantTopOnly.policy @@ -0,0 +1,4 @@ +// policy file that grants read access to source directory +grant { + permission java.io.FilePermission "${test.src}", "read"; +}; diff --git a/test/tools/launcher/6842838/CreateBadJar.java b/test/tools/launcher/6842838/CreateBadJar.java new file mode 100644 index 0000000000000000000000000000000000000000..dfdc9163de2962ecd8abef0a6b62466151d75cb5 --- /dev/null +++ b/test/tools/launcher/6842838/CreateBadJar.java @@ -0,0 +1,168 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * Borrowing significantly from Martin Buchholz's CorruptedZipFiles.java + * + * Needed a way of testing the checks for corrupt zip/jar entry in + * inflate_file from file j2se/src/share/bin/parse_manifest.c + * and running them with the 64-bit launcher. e.g. + * sparcv9/bin/java -jar badjar.jar + * + * Run from a script driver Test6842838.sh as we want to specifically run + * bin/sparcv9/java, the 64-bit launcher. + * + * So this program will create a zip file and damage it in the way + * required to tickle this bug. + * + * It will cause a buffer overrun: but that will not always crash. + * Use libumem preloaded by the script driver in order to + * abort quickly when the overrun happens. That makes the test + * Solaris-specific. + */ + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import static java.lang.System.*; +import static java.util.zip.ZipFile.*; + +public class CreateBadJar { + +public static void main(String [] arguments) { + + if (arguments.length != 2) { + throw new RuntimeException("Arguments: jarfilename entryname"); + } + String outFile = arguments[0]; + String entryName = arguments[1]; + + try { + // If the named file doesn't exist, create it. + // If it does, we are expecting it to contain the named entry, for + // alteration. + if (!new File(outFile).exists()) { + System.out.println("Creating file " + outFile); + + // Create the requested zip/jar file. + ZipOutputStream zos = null; + zos = new ZipOutputStream( + new FileOutputStream(outFile)); + + ZipEntry e = new ZipEntry(entryName); + zos.putNextEntry(e); + for (int j=0; j<50000; j++) { + zos.write((int)'a'); + } + zos.closeEntry(); + zos.close(); + zos = null; + } + + // Read it. + int len = (int)(new File(outFile).length()); + byte[] good = new byte[len]; + FileInputStream fis = new FileInputStream(outFile); + fis.read(good); + fis.close(); + fis = null; + + int endpos = len - ENDHDR; + int cenpos = u16(good, endpos+ENDOFF); + if (u32(good, cenpos) != CENSIG) throw new RuntimeException("Where's CENSIG?"); + + byte[] bad; + bad = good.clone(); + + // Corrupt it... + int pos = findInCEN(bad, cenpos, entryName); + + // What bad stuff are we doing to it? + // Store a 32-bit -1 in uncomp size. + bad[pos+0x18]=(byte)0xff; + bad[pos+0x19]=(byte)0xff; + bad[pos+0x1a]=(byte)0xff; + bad[pos+0x1b]=(byte)0xff; + + // Bad work complete, delete the original. + new File(outFile).delete(); + + // Write it. + FileOutputStream fos = new FileOutputStream(outFile); + fos.write(bad); + fos.close(); + fos = null; + + } catch (Exception e) { + e.printStackTrace(); + } + +} + + /* + * Scan Central Directory File Headers looking for the named entry. + */ + + static int findInCEN(byte[] bytes, int cenpos, String entryName) { + int pos = cenpos; + int nextPos = 0; + String filename = null; + do { + if (nextPos != 0) { + pos = nextPos; + } + System.out.println("entry at pos = " + pos); + if (u32(bytes, pos) != CENSIG) throw new RuntimeException ("entry not found in CEN or premature end..."); + + int csize = u32(bytes, pos+0x14); // +0x14 1 dword csize + int uncompsize = u32(bytes, pos+0x18); // +0x18 1 dword uncomp size + int filenameLength = u16(bytes, pos+0x1c); // +0x1c 1 word length of filename + int extraLength = u16(bytes, pos+0x1e); // +0x1e 1 world length of extra field + int commentLength = u16(bytes, pos+0x20); // +0x20 1 world length of file comment + filename = new String(bytes, pos+0x2e, filenameLength); // +0x2e chars of filename + int offset = u32(bytes, pos+0x2a); // +0x2a chars of filename + + System.out.println("filename = " + filename + "\ncsize = " + csize + + " uncomp.size = " + uncompsize +" file offset = " + offset); + nextPos = pos + 0x2e + filenameLength + extraLength + commentLength; + + } while (!filename.equals(entryName)); + + System.out.println("entry found at pos = " + pos); + return pos; + } + + static int u8(byte[] data, int offset) { + return data[offset]&0xff; + } + + static int u16(byte[] data, int offset) { + return u8(data,offset) + (u8(data,offset+1)<<8); + } + + static int u32(byte[] data, int offset) { + return u16(data,offset) + (u16(data,offset+2)<<16); + } + +} + diff --git a/test/tools/launcher/6842838/Test6842838.sh b/test/tools/launcher/6842838/Test6842838.sh new file mode 100644 index 0000000000000000000000000000000000000000..5209ab4e10f51f752930cbc1515cdb8a981959b2 --- /dev/null +++ b/test/tools/launcher/6842838/Test6842838.sh @@ -0,0 +1,75 @@ +#!/bin/sh -x + +# +# @test @(#)Test6842838.sh +# @bug 6842838 +# @summary Test 6842838 64-bit launcher failure due to corrupt jar +# @run shell Test6842838.sh +# + +# +# Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +if [ "${TESTSRC}" = "" ] +then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS ) + NULL=/dev/null + PS=":" + FS="/" + JAVA_EXE=${TESTJAVA}${FS}bin${FS}sparcv9${FS}java + ;; + * ) + echo "Only testing on sparcv9 (use libumem to reliably catch buffer overrun)" + exit 0; + ;; +esac + +BADFILE=newbadjar.jar + +${JAVA_EXE} -version +rm -f ${BADFILE} +${TESTJAVA}/bin/javac CreateBadJar.java +${JAVA_EXE} CreateBadJar ${BADFILE} "META-INF/MANIFEST.MF" +LD_PRELOAD=/lib/64/libumem.so ${JAVA_EXE} -jar ${BADFILE} > test.out 2>&1 + +grep "Invalid or corrupt jarfile" test.out +exit $?