<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    Hello Vincent<br>
    <br>
    Here may be the fix for JDK-6695402. First a test.<br>
    <br>
    BEGIN
    /jdk10/jdk/test/sun/security/tools/jarsigner/MultibyteUnicodeName.java<br>
    /*<br>
     * Copyright (c) 1999, Oracle and/or its affiliates. All rights
    reserved.<br>
     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.<br>
     *<br>
     * This code is free software; you can redistribute it and/or modify
    it<br>
     * under the terms of the GNU General Public License version 2 only,
    as<br>
     * published by the Free Software Foundation.<br>
     *<br>
     * This code is distributed in the hope that it will be useful, but
    WITHOUT<br>
     * ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or<br>
     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    License<br>
     * version 2 for more details (a copy is included in the LICENSE
    file that<br>
     * accompanied this code).<br>
     *<br>
     * You should have received a copy of the GNU General Public License
    version<br>
     * 2 along with this work; if not, write to the Free Software
    Foundation,<br>
     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.<br>
     *<br>
     * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA
    94065 USA<br>
     * or visit <a class="moz-txt-link-abbreviated" href="http://www.oracle.com">www.oracle.com</a> if you need additional information or
    have any<br>
     * questions.<br>
     */<br>
    <br>
    /*<br>
     * @test<br>
     * @bug JDK-6695402<br>
     * @summary verify signatures of jars containing classes with names
    with multi-<br>
     *          byte unicode characters broken across lines<br>
     * @library /test/lib<br>
     * @modules jdk.jartool/sun.tools.jar<br>
     *          jdk.jartool/sun.security.tools.jarsigner<br>
     * @build jdk.test.lib.JDKToolLauncher<br>
     *        jdk.test.lib.process.*<br>
     * @run main MultibyteUnicodeName<br>
     */<br>
    <br>
    import java.io.ByteArrayOutputStream;<br>
    import java.io.IOException;<br>
    import java.io.InputStream;<br>
    import java.io.UnsupportedEncodingException;<br>
    import java.nio.file.Files;<br>
    import java.nio.file.Paths;<br>
    import java.util.jar.JarFile;<br>
    import java.util.jar.Manifest;<br>
    import java.util.stream.Collectors;<br>
    import java.util.Arrays;<br>
    import java.util.Map;<br>
    import java.util.jar.Attributes.Name;<br>
    import java.util.jar.JarEntry;<br>
    <br>
    import static java.nio.charset.StandardCharsets.UTF_8;<br>
    <br>
    import sun.security.tools.jarsigner.Resources;<br>
    <br>
    import jdk.test.lib.JDKToolLauncher;<br>
    import jdk.test.lib.process.OutputAnalyzer;<br>
    import jdk.test.lib.process.ProcessTools;<br>
    <br>
    public class MultibyteUnicodeName {<br>
        <br>
        public static void main(String[] args) throws Throwable {<br>
            try {<br>
                prepare();<br>
                <br>
                testSignJar("test.jar");<br>
                testSignJarNoManifest("test-no-manifest.jar");<br>
                testSignJarUpdate("test-update.jar");<br>
                testSignJarWithIndex("test-index.jar");<br>
                testSignJarAddIndex("test-add-index.jar");<br>
                <br>
            } finally {<br>
                Files.deleteIfExists(Paths.get(keystoreFileName));<br>
                Files.deleteIfExists(Paths.get(ManifestFileName));<br>
                Files.deleteIfExists(Paths.get(refClassFilename));<br>
                Files.deleteIfExists(Paths.get(testClassFilename));<br>
            }<br>
        }<br>
        <br>
        static final String alias = "a";<br>
        static final String keystoreFileName = "test.jks";<br>
        static final String ManifestFileName = "MANIFEST.MF";<br>
        <br>
        static class A1234567890B1234567890C1234567890D12345678exyz { }<br>
        static class A1234567890B1234567890C1234567890D12345678éxyz { }<br>
        <br>
        static final String refClassFilename =
    MultibyteUnicodeName.class.getSimpleName() + <br>
                "$" +
    A1234567890B1234567890C1234567890D12345678exyz.class.getSimpleName()
    + ".class";<br>
        static final String testClassFilename =
    MultibyteUnicodeName.class.getSimpleName() + <br>
                "$" +
    A1234567890B1234567890C1234567890D12345678éxyz.class.getSimpleName()
    + ".class";<br>
        <br>
        static void prepare() throws Throwable {<br>
            tool("keytool", "-keystore", keystoreFileName,
    "-genkeypair", "-storepass", "changeit",<br>
                    "-keypass", "changeit", "-storetype", "JKS",
    "-alias", alias, "-dname", "CN=X",<br>
                    "-validity", "366")<br>
                    .shouldHaveExitValue(0);<br>
            <br>
            Files.write(Paths.get(ManifestFileName),<br>
                    (Name.MANIFEST_VERSION.toString() + ":
    1.0\r\n").getBytes(UTF_8.name()));<br>
            copyClassToFile(refClassFilename);<br>
            copyClassToFile(testClassFilename);<br>
        }<br>
        <br>
        static void copyClassToFile(String classFilename) throws
    IOException {<br>
            try (<br>
                InputStream asStream =
    MultibyteUnicodeName.class.getResourceAsStream(classFilename);<br>
                ByteArrayOutputStream buf = new ByteArrayOutputStream();<br>
            ) {<br>
                int b;<br>
                while ((b = asStream.read()) != -1) buf.write(b);<br>
                Files.write(Paths.get(classFilename),
    buf.toByteArray());<br>
            }<br>
        }<br>
    <br>
        static void testSignJar(String jarFileName) throws Throwable {<br>
            try {<br>
                tool("jar", "cvfm", jarFileName, <br>
                        ManifestFileName, refClassFilename,
    testClassFilename)<br>
                        .shouldHaveExitValue(0);<br>
                verifyJarSignature(jarFileName);<br>
    <br>
            } finally {<br>
                Files.deleteIfExists(Paths.get(jarFileName));<br>
            }<br>
        }<br>
    <br>
        static void testSignJarNoManifest(String jarFileName) throws
    Throwable {<br>
            try {<br>
                tool("jar", "cvf", jarFileName, refClassFilename,
    testClassFilename)<br>
                    .shouldHaveExitValue(0);<br>
                verifyJarSignature(jarFileName);<br>
    <br>
            } finally {<br>
                Files.deleteIfExists(Paths.get(jarFileName));<br>
            }<br>
        }<br>
        <br>
        static void testSignJarUpdate(String jarFileName) throws
    Throwable {<br>
            try {<br>
                tool("jar", "cvfm", jarFileName, ManifestFileName,
    refClassFilename)<br>
                    .shouldHaveExitValue(0);<br>
                tool("jarsigner", "-keystore", keystoreFileName,
    "-storetype", "JKS",<br>
                        "-storepass", "changeit", "-debug", jarFileName,
    alias)<br>
                    .shouldHaveExitValue(0);<br>
                tool("jar", "uvf", jarFileName, testClassFilename)<br>
                    .shouldHaveExitValue(0);<br>
                verifyJarSignature(jarFileName);<br>
    <br>
            } finally {<br>
                Files.deleteIfExists(Paths.get(jarFileName));<br>
            }<br>
        }<br>
        <br>
        static void testSignJarWithIndex(String jarFileName) throws
    Throwable {<br>
            try {<br>
                tool("jar", "cvfm", jarFileName, <br>
                        ManifestFileName, refClassFilename,
    testClassFilename)<br>
                    .shouldHaveExitValue(0);<br>
                tool("jar", "iv", jarFileName).shouldHaveExitValue(0);<br>
                verifyJarSignature(jarFileName);<br>
    <br>
            } finally {<br>
                Files.deleteIfExists(Paths.get(jarFileName));<br>
            }<br>
        }<br>
    <br>
        static void testSignJarAddIndex(String jarFileName) throws
    Throwable {<br>
            try {<br>
                tool("jar", "cvfm", jarFileName, <br>
                        ManifestFileName, refClassFilename,
    testClassFilename)<br>
                    .shouldHaveExitValue(0);<br>
                tool("jarsigner", "-keystore", keystoreFileName,
    "-storetype", "JKS",<br>
                        "-storepass", "changeit", "-debug", jarFileName,
    alias)<br>
                    .shouldHaveExitValue(0);<br>
                tool("jar", "iv", jarFileName).shouldHaveExitValue(0);<br>
                verifyJarSignature(jarFileName);<br>
    <br>
            } finally {<br>
                Files.deleteIfExists(Paths.get(jarFileName));<br>
            }<br>
        }<br>
        <br>
        static Map<String, String> jarsignerResources =
    Arrays.stream(new Resources().getContents()).<br>
                collect(Collectors.toMap(e -> (String) e[0], e ->
    (String) e[1]));<br>
                <br>
        static void verifyJarSignature(String jarFileName) throws
    Throwable {<br>
            // actually sign the jar<br>
            tool("jarsigner", "-keystore", keystoreFileName,
    "-storetype", "JKS",<br>
                    "-storepass", "changeit", "-debug", jarFileName,
    alias)<br>
                    .shouldHaveExitValue(0);<br>
            <br>
            verifyClassNameLineBroken(jarFileName);<br>
            <br>
            // check for no unsigned entries<br>
            tool("jarsigner", "-verify", "-keystore", keystoreFileName,
    "-storetype", "JKS",<br>
                    "-storepass", "changeit", "-debug", jarFileName,
    alias)<br>
                    .shouldHaveExitValue(0)<br>
                    .shouldNotContain(jarsignerResources.get(<br>
                           
"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));<br>
            <br>
            // check that both classes with and without multi-byte
    unicode characters in their names are signed<br>
            tool("jarsigner", "-verify", "-verbose", "-keystore",
    keystoreFileName, "-storetype", "JKS",<br>
                    "-storepass", "changeit", "-debug", jarFileName,
    alias)<br>
                    .shouldHaveExitValue(0)<br>
                    .shouldMatch("^" + jarsignerResources.get("s") +
    jarsignerResources.get("m") + jarsignerResources.get("k") + ".+" +
    refClassFilename.replaceAll("\\$", "\\\\\\$") + "$")<br>
                    .shouldMatch("^" + jarsignerResources.get("s") +
    jarsignerResources.get("m") + jarsignerResources.get("k") + ".+" +
    testClassFilename.replaceAll("\\$", "\\\\\\$") + "$");<br>
            <br>
            // check that both classes with and without multi-byte
    unicode characters in their names have signing certificates<br>
            tool("jarsigner", "-verify", "-verbose", "-certs",
    "-keystore", keystoreFileName, <br>
                    "-storetype", "JKS", "-storepass", "changeit",
    "-debug", jarFileName, alias)<br>
                    .shouldHaveExitValue(0)<br>
                    .shouldMatch(refClassFilename.replaceAll("\\$",
    "\\\\\\$") + "\\s*\\R*\\s*(\\[" +
    jarsignerResources.get("entry.was.signed.on") + "
    .*\\]\\R*)?\\s*X.509, CN=X \\(" + alias + "\\)")<br>
                    .shouldMatch(testClassFilename.replaceAll("\\$",
    "\\\\\\$") + "\\s*\\R*\\s*(\\[" +
    jarsignerResources.get("entry.was.signed.on") + "
    .*\\]\\R*)?\\s*X.509, CN=X \\(" + alias + "\\)");<br>
        }<br>
        <br>
        /**<br>
         * it would be too easy to miss the actual test case by just
    renaming an identifier so that<br>
         * the multi-byte encoded character would not any longer be
    broken across a line break.<br>
         *<br>
         * this test verifies that the actual test case is tested based
    on the manifest<br>
         * and not based on the signature file because at the moment,
    the signature file<br>
         * does not even contain the desired entry at all.<br>
         *<br>
         * this relies on the Manifest breaking lines unaware of bytes
    that belong to the same<br>
         * multi-ybte utf characters.<br>
         */<br>
        static void verifyClassNameLineBroken(String jarFileName) throws
    IOException {<br>
            byte[] eAcute = "é".getBytes(UTF_8);<br>
            byte[] eAcuteBroken = new byte[] {eAcute[0], '\r', '\n', '
    ', eAcute[1]};<br>
            <br>
            try (<br>
                JarFile jar = new JarFile(jarFileName);<br>
            ) {<br>
                if (jar.getManifest().getAttributes(testClassFilename)
    == null) {<br>
                    throw new AssertionError(testClassFilename + " not
    found in manifest");<br>
                }<br>
                <br>
                JarEntry manifestEntry =
    jar.getJarEntry(JarFile.MANIFEST_NAME);<br>
                try (<br>
                    InputStream manifestIs =
    jar.getInputStream(manifestEntry);<br>
                ) {<br>
                    int bytesMatched = 0;<br>
                    for (int b = manifestIs.read(); b > -1; b =
    manifestIs.read()) {<br>
                        if ((byte) b == eAcuteBroken[bytesMatched]) {<br>
                            bytesMatched++;<br>
                            if (bytesMatched == eAcuteBroken.length) {<br>
                                break;<br>
                            }<br>
                        } else {<br>
                            bytesMatched = 0;<br>
                        }<br>
                    }<br>
                    if (bytesMatched < eAcuteBroken.length) {<br>
                        throw new AssertionError("self-test failed: "<br>
                                + "multi-byte utf-8 character not broken
    across lines");<br>
                    }<br>
                }<br>
            }<br>
        }<br>
        <br>
        static OutputAnalyzer tool(String tool, String... args)<br>
                throws Throwable {<br>
            JDKToolLauncher l =
    JDKToolLauncher.createUsingTestJDK(tool);<br>
            for (String arg : args) {<br>
                if (arg .startsWith("-J")) {<br>
                    l.addVMArg(arg.substring(2));<br>
                } else {<br>
                    l.addToolArg(arg);<br>
                }<br>
            }<br>
            return ProcessTools.executeCommand(l.getCommand());<br>
        }<br>
        <br>
    }<br>
    END
    /jdk10/jdk/test/sun/security/tools/jarsigner/MultibyteUnicodeName.java<br>
    <br>
    <br>
    There are three e with acutes, on lines 84, 89, and 227, just in
    case the mail suffers bad encoding which might not be absolutely
    unconceivable regarding the bug's subject.<br>
    <br>
    In contrast to the bug description it uses a nested class with a
    two-byte UTF-8 character rather than one in its own file. I chose to
    do it that way because then the complete test goes into one file and
    therefore I assume the overview is kept easier. The test still
    demonstrates exactly JDK-6695402's problem.<br>
    <br>
    It may not have been necessary to also test jar files with indexes
    but i consider it necessary to have signing unsigned as well as
    partially signed jars tested, so why not have one more case tested,
    too?<br>
    <br>
    There might also be a more elegant approach to get class files into
    a jar file as to get their contents through the class loader. I
    chose to use real class files rather than dummy contents in files
    named *.class or for instance plain text files in the jar the
    signing of which to be tested in order to stay as close to the
    original bug problem as possible even though I don't have any notion
    that it would make a difference. The amount of code used to copy the
    class file contents around is comparatively small with respect to
    the whole test case amount of code.<br>
      <br>
    For the demonstration that the multi-byte character actually makes
    the alleged difference, I concluded that it was necessary to have
    another class name not previously affected by the bug in order to
    compare the effects of just different names. Otherwise the signing
    could fail to any other reason undetectably.<br>
    <br>
    In order to express a condition to tell successful from failed test
    runs the best approach I found was to analyze the jarsigner tool's
    output which is in my opinion not the most desirable option. I'd
    have preferred output from a clearer structured api but then I guess
    the output format will not change too often in the foreseeable
    future. For instance the check for the s, m, and k flags is more
    pragmatical approach than obviously perfectly failsafe when
    operating with regular expressions to match it with the output.
    Other parts such as 'X.509' and 'CN=' are not even jarsigner tool
    resources. I put at least a reference to
    sun.security.tools.jarsigner.Resources.<br>
    <br>
    Finally, I afforded kind of a self-test that protects the test from
    undetected failing because renaming the main class which would move
    the two-byte unicode character to a position not suitable for the
    test. It may not be absolutely necessary.<br>
    <br>
    <br>
    <br>
    BEGIN PATH<br>
    diff -r ddc25f646c2e
    src/java.base/share/classes/sun/security/util/ManifestDigester.java<br>
    ---
    a/src/java.base/share/classes/sun/security/util/ManifestDigester.java   
    Thu Aug 31 22:21:20 2017 -0700<br>
    +++
    b/src/java.base/share/classes/sun/security/util/ManifestDigester.java   
    Wed Sep 20 00:56:15 2017 +0200<br>
    @@ -28,6 +28,7 @@<br>
     import java.security.*;<br>
     import java.util.HashMap;<br>
     import java.io.ByteArrayOutputStream;<br>
    +import static java.nio.charset.StandardCharsets.UTF_8;<br>
     <br>
     /**<br>
      * This class is used to compute digests on sections of the
    Manifest.<br>
    @@ -112,7 +113,7 @@<br>
             rawBytes = bytes;<br>
             entries = new HashMap<>();<br>
     <br>
    -        ByteArrayOutputStream baos = new ByteArrayOutputStream();<br>
    +        ByteArrayOutputStream nameBuf = new
    ByteArrayOutputStream();<br>
     <br>
             Position pos = new Position();<br>
     <br>
    @@ -131,50 +132,40 @@<br>
     <br>
                 if (len > 6) {<br>
                     if (isNameAttr(bytes, start)) {<br>
    -                    StringBuilder nameBuf = new
    StringBuilder(sectionLen);<br>
    +                    nameBuf.reset();<br>
    +                    nameBuf.write(bytes, start+6, len-6);<br>
     <br>
    -                    try {<br>
    -                        nameBuf.append(<br>
    -                            new String(bytes, start+6, len-6,
    "UTF8"));<br>
    +                    int i = start + len;<br>
    +                    if ((i-start) < sectionLen) {<br>
    +                        if (bytes[i] == '\r') {<br>
    +                            i += 2;<br>
    +                        } else {<br>
    +                            i += 1;<br>
    +                        }<br>
    +                    }<br>
     <br>
    -                        int i = start + len;<br>
    -                        if ((i-start) < sectionLen) {<br>
    -                            if (bytes[i] == '\r') {<br>
    -                                i += 2;<br>
    -                            } else {<br>
    -                                i += 1;<br>
    -                            }<br>
    +                    while ((i-start) < sectionLen) {<br>
    +                        if (bytes[i++] == ' ') {<br>
    +                            // name is wrapped<br>
    +                            int wrapStart = i;<br>
    +                            while (((i-start) < sectionLen)<br>
    +                                    && (bytes[i++] !=
    '\n'));<br>
    +                            if (bytes[i-1] != '\n')<br>
    +                                return; // XXX: exception?<br>
    +                            int wrapLen;<br>
    +                            if (bytes[i-2] == '\r')<br>
    +                                wrapLen = i-wrapStart-2;<br>
    +                            else<br>
    +                                wrapLen = i-wrapStart-1;<br>
    +<br>
    +                            nameBuf.write(bytes, wrapStart,
    wrapLen);<br>
    +                        } else {<br>
    +                            break;<br>
                             }<br>
    +                    }<br>
     <br>
    -                        while ((i-start) < sectionLen) {<br>
    -                            if (bytes[i++] == ' ') {<br>
    -                                // name is wrapped<br>
    -                                int wrapStart = i;<br>
    -                                while (((i-start) < sectionLen)<br>
    -                                        && (bytes[i++] !=
    '\n'));<br>
    -                                    if (bytes[i-1] != '\n')<br>
    -                                        return; // XXX: exception?<br>
    -                                    int wrapLen;<br>
    -                                    if (bytes[i-2] == '\r')<br>
    -                                        wrapLen = i-wrapStart-2;<br>
    -                                    else<br>
    -                                        wrapLen = i-wrapStart-1;<br>
    -<br>
    -                            nameBuf.append(new String(bytes,
    wrapStart,<br>
    -                                                      wrapLen,
    "UTF8"));<br>
    -                            } else {<br>
    -                                break;<br>
    -                            }<br>
    -                        }<br>
    -<br>
    -                        entries.put(nameBuf.toString(),<br>
    -                            new Entry(start, sectionLen,
    sectionLenWithBlank,<br>
    -                                rawBytes));<br>
    -<br>
    -                    } catch (java.io.UnsupportedEncodingException
    uee) {<br>
    -                        throw new IllegalStateException(<br>
    -                            "UTF8 not available on platform");<br>
    -                    }<br>
    +                    entries.put(new String(nameBuf.toByteArray(),
    UTF_8),<br>
    +                        new Entry(start, sectionLen,
    sectionLenWithBlank, rawBytes));<br>
                     }<br>
                 }<br>
                 start = pos.startOfNext;<br>
    END PATCH<br>
    <br>
    <br>
    The patch is mostly so big because indentation has changed in many
    lines.<br>
    <br>
    There was baos there before without apparent use. The patch renames
    it and puts it into use. It came in very handy because if it would
    not have been there already, I would have had to defined one of my
    own.<br>
    <br>
    The main point of the patch is that manifest section names that are
    broken across lines at possibly arbitrary bytes are no longer
    converted into strings for each manifest line and then joined. Parts
    of names broken across lines are now joined first when they are
    still byte sequences and only when the complete byte sequence is
    available after processing all manifest lines that contain the same
    manifest section name decoded into a unicode string.<br>
    <br>
    For decoding the bytes into a string I chose a different string
    constructor than was used before that does not any longer declare
    UnsupportedEncodingException rendering the try/catch redundant. It
    couldn't have ever occurred anyway taking into consideration that
    UTF-8 is mandatory for every Java platform, StandardCharsets says.
    The difference according to the documentation is that the previously
    used String constructor returned undefined strings for invalid byte
    sequences whereas the one used in the patch will replace unparseable
    portions with valid 'unknown' characters.<br>
    <br>
    One question I cannot still answer yet is how the ManifestDigester
    can be changed at all without complete test coverage or risking to
    break existing signatures. I already started on that but it's quite
    a piece of work to almost formally prove that all manifests will
    continue to produce identical digests, except of course for the ones
    now fixed.<br>
    <br>
    Regards,<br>
    Philipp<br>
    <br>
    <br>
    <div class="moz-cite-prefix">On 17.09.2017 21:25, Philipp Kunz
      wrote:<br>
    </div>
    <blockquote
      cite="mid:f22cd9f8-3e45-5a63-c7f2-e237323c8c21@paratix.ch"
      type="cite">
      <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
      Hello Vincent<br>
      <br>
      I narrowed the error down so far and suspect now that it is an
      effect of sun.security.util.ManifestDigester's constructor, lines
      134 and 163-164, in combination with
      java.util.jar.Manifest.make72Safe. Manifest breaks multi-byte
      characters in manifest section names across lines and
      ManifestDigester fails to restore them correctly, which both
      sounds wrong but ManifestDigester sure is.<br>
      <br>
      Just fixing it would be too tempting but then I would not know (I
      mean not know for sure with evidence from tests) if any existing
      jar-signature would still be valid and I don't want to break
      existing signatures. When I had a look at the tests specific for
      Manifest and ManifestDigester I found very little. There are many
      more different situations and corner cases and combinations
      thereof to cover with tests than it looks like at first glance so
      that writing tests that cover all relevant cases looks to me like
      quite an effort. I have the impression that test coverage was not
      a priority when the subjected code was developed or at least the
      tests might not have been contributed to the open JDK project.
      Hence, while I'm continuing to complete these tests I miss, if
      someone has an idea how to simplify that so that I can still
      convince at least myself that no existing signature will break or
      where possibly more testcases are that I haven't discovered so
      far, please let me know.<br>
      <br>
      I'm also wondering how much performance should be taken into
      consideration. There are a few hints such as reusing byte arrays
      that suggest that it is an issue. Will a patch be rejected if it
      slows down some tests beyond a certain limit for so little added
      value or what might be the acceptance criteria here? I don't
      expect insuperable difficulties with performance but would still
      appreciate some general idea.<br>
      <br>
      My desired or currently preferred approach to fix JDK-6695402
      would be to let ManifestDigester any kind of use or extend
      Manifest in order to let Manifest identify the manifest sections
      thereby preventing the parsing duplicated that identifies the
      manifest sections.<br>
      <br>
      As a new contributor I could use and would appreciate some
      guidance particularly about what kind and completeness of test
      coverage and performance tuning applies or is suggested in the
      context of the given bug. Otherwise I fear I might contribute too
      many tests which would have to be reviewed and maintained or quite
      some work would be for nothing if a patch would not satisfy
      performance requirements.<br>
      <br>
      Regards,<br>
      Philipp<br>
      <br>
      <br>
      <br>
      <div class="moz-cite-prefix">On 01.09.2017 15:20, Vincent Ryan
        wrote:<br>
      </div>
      <blockquote
        cite="mid:843FC180-8128-4638-97B5-DEBA3C9E6FDC@oracle.com"
        type="cite">
        <meta http-equiv="Content-Type" content="text/html;
          charset=utf-8">
        That all sounds fine. Let me know when your patch is ready to
        submit.
        <div class="">Thanks.<br class="">
          <div class=""><br class="">
          </div>
          <div class=""><br class="">
            <div>
              <blockquote type="cite" class="">
                <div class="">On 1 Sep 2017, at 13:15, Philipp Kunz <<a
                    moz-do-not-send="true"
                    href="mailto:philipp.kunz@paratix.ch" class="">philipp.kunz@paratix.ch</a>>
                  wrote:</div>
                <br class="Apple-interchange-newline">
                <div class="">
                  <meta content="text/html; charset=utf-8"
                    http-equiv="Content-Type" class="">
                  <div bgcolor="#FFFFFF" text="#000000" class=""> Hello
                    Vincent<br class="">
                    <br class="">
                    Thank you for sponsoring!<br class="">
                    So far, I have become a contributor by signing the
                    OCA which has been accepted. Dalibor Topic wrote
                    that he can confirm and it's also here: <a
                      moz-do-not-send="true"
                      class="moz-txt-link-freetext"
                      href="http://www.oracle.com/technetwork/community/oca-486395.html#p">http://www.oracle.com/technetwork/community/oca-486395.html#p</a>
                    -> Paratix GmbH<br class="">
                    Therefore I think I have followed the steps in <a
                      moz-do-not-send="true"
                      href="http://openjdk.java.net/contribute/"
                      class="">http://openjdk.java.net/contribute/</a>
                    at least the ones before actual patch submission.<br
                      class="">
                    <br class="">
                    Currently, I'm working on getting the existing test
                    cases running locally. Unfortunately, I started with
                    jdk 9 and switched to 10 now. I figured these
                    commands run at least the relevant tests with 9 and
                    hope this also applies to 10:<br class="">
                    make run-test-tier1<br class="">
                    make run-test TEST="jdk/test"<br class="">
                    they report errors and failures but it hasn't been
                    completed and released which might explain it. If I
                    run the tests I assume relevant for my patch<br
                      class="">
                    make run-test
                    TEST="jtreg:jdk/test/sun/security/tools/jarsigner
                    jtreg:jdk/test/java/util/jar"<br class="">
                    then it reports zero errors and failures which may
                    be a good starting point.<br class="">
                    Do you think that sounds reasonable or do you have
                    another suggestion how to run the tests?<br class="">
                    <br class="">
                    Next, I will add a test for JDK-6695402 before
                    actually fixing it. As an example, I'll try
                    something in the style of <a moz-do-not-send="true"
                      class="moz-txt-link-freetext"
href="http://hg.openjdk.java.net/jdk9/dev/jdk/file/65464a307408/test/java/util/jar/Manifest/CreateManifest.java">http://hg.openjdk.java.net/jdk9/dev/jdk/file/65464a307408/test/java/util/jar/Manifest/CreateManifest.java</a>.
                    This way, I try to demonstrate the improvement.<br
                      class="">
                    <br class="">
                    I guess I have identified the following line as the
                    cause: <span id="l157" class="">value = new
                      String(vb, 0, 0, vb.length);<br class="">
                    </span><a moz-do-not-send="true"
                      class="moz-txt-link-freetext"
href="http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/51f5d60713b5/src/java.base/share/classes/java/util/jar/Manifest.java#l157">http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/51f5d60713b5/src/java.base/share/classes/java/util/jar/Manifest.java#l157</a><br
                      class="">
                    So I'll try to remove it first including the whole
                    four line if block.<br class="">
                    <br class="">
                    Philipp<br class="">
                    <br class="">
                    <br class="">
                    <div class="moz-cite-prefix">On 01.09.2017 10:00,
                      Vincent Ryan wrote:<br class="">
                    </div>
                    <blockquote
                      cite="mid:2BE6B2AD-1896-4F22-A948-D494BA11F33A@oracle.com"
                      type="cite" class="">
                      <meta http-equiv="Content-Type"
                        content="text/html; charset=utf-8" class="">
                      <div class="">Hello Philipp,
                        <div class=""><br class="">
                        </div>
                        <div class="">I’m happy to sponsor your fix for
                          JDK 10. Have you followed these steps: <a
                            moz-do-not-send="true"
                            href="http://openjdk.java.net/contribute/"
                            class="">http://openjdk.java.net/contribute/</a> ?</div>
                        <div class=""><br class="">
                        </div>
                        <div class="">Thanks.</div>
                      </div>
                      <div class=""><br class="">
                      </div>
                      <br class="">
                      <div class="">
                        <blockquote type="cite" class="">
                          <div class="">On 1 Sep 2017, at 08:58, Vincent
                            Ryan <<a moz-do-not-send="true"
                              href="mailto:vincent.x.ryan@oracle.com"
                              class="">vincent.x.ryan@oracle.com</a>>
                            wrote:</div>
                          <br class="Apple-interchange-newline">
                          <div class="">
                            <div class="">Moved to security-dev<br
                                class="">
                              <br class="">
                              <br class="">
                              <blockquote type="cite" class="">On 1 Sep
                                2017, at 08:28, Philipp Kunz <<a
                                  moz-do-not-send="true"
                                  href="mailto:philipp.kunz@paratix.ch"
                                  class="">philipp.kunz@paratix.ch</a>>
                                wrote:<br class="">
                                <br class="">
                                Hello everyone<br class="">
                                <br class="">
                                I have been developing with Java for
                                around 17 years now and when I
                                encountered some bug I decided to
                                attempt to fix it: <a
                                  moz-do-not-send="true"
                                  href="https://bugs.openjdk.java.net/browse/JDK-6695402"
                                  class="">https://bugs.openjdk.java.net/browse/JDK-6695402</a>.
                                This also looks like it may not be too
                                big a piece for a first contribution.<br
                                  class="">
                                <br class="">
                                I read through quite some guides and all
                                kinds of documents but could not yet
                                help myself with the following
                                questions:<br class="">
                                <br class="">
                                May I login to jira to add comments to
                                bugs? If so, how would I request or
                                receive credentials? Or are mailing
                                lists preferred?<br class="">
                                <br class="">
                                Another question is whether I should
                                apply it to jdk9, but it may be too late
                                now, or to jdk10, and backporting can be
                                considered later. Probably it wouldn't
                                even make much a difference for the
                                patch itself.<br class="">
                                <br class="">
                                One more question I have is how or where
                                to find the sources from before
                                migration to mercurial. Because some
                                lines of code I intend to change go back
                                farther and in the history I find only
                                'initial commit'. With such a history I
                                might be able better to understand why
                                it's there and prevent to make the same
                                mistake again.<br class="">
                                <br class="">
                                I guess the appropriate mailing list for
                                above mentioned bug is security-dev. Is
                                it correct that I can send a patch there
                                and just hope for some sponsor to pick
                                it up? Of course I'd be glad if some
                                sponsor would contact me and maybe
                                provide some assistance or if someone
                                would confirm that sending a patch to
                                the mailing list is the right way to
                                find a sponsor.<br class="">
                                <br class="">
                                Philipp Kunz<br class="">
                              </blockquote>
                              <br class="">
                            </div>
                          </div>
                        </blockquote>
                      </div>
                      <br class="">
                    </blockquote>
                    <br class="">
                  </div>
                </div>
              </blockquote>
            </div>
            <br class="">
          </div>
        </div>
      </blockquote>
      <br>
      <div class="moz-signature"><br>
        <br>
        <br>
        <hr size="2" width="100%"><br>
        <img shrinktofit="true"
          src="cid:part10.5AC2A39E.12348735@paratix.ch" align="bottom"
          border="0"><br>
        <br>
        Paratix GmbH<br>
        St Peterhofstatt 11<br>
        8001 Zürich<br>
        <br>
        +41 (0)76 397 79 35<br>
        <a moz-do-not-send="true" href="mailto:philipp.kunz@paratix.ch">philipp.kunz@paratix.ch</a>
      </div>
    </blockquote>
    <br>
  </body>
</html>