1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4811968 6908628 8006564
  27  * @modules java.base/sun.security.util
  28  * @run main S11N check
  29  * @summary Serialization compatibility with old versions (and fixes)
  30  */
  31 
  32 import java.io.ByteArrayInputStream;
  33 import java.io.ByteArrayOutputStream;
  34 import java.io.ObjectInputStream;
  35 import java.io.ObjectOutputStream;
  36 import java.lang.reflect.Method;
  37 import java.util.HashMap;
  38 import java.util.Map;
  39 import sun.security.util.ObjectIdentifier;
  40 
  41 public class S11N {
  42     static String[] SMALL= {
  43         "0.0",
  44         "1.1",
  45         "2.2",
  46         "1.2.3456",
  47         "1.2.2147483647.4",
  48         "1.2.268435456.4",
  49     };
  50 
  51     static String[] HUGE = {
  52         "2.16.764.1.3101555394.1.0.100.2.1",
  53         "1.2.2147483648.4",
  54         "2.3.4444444444444444444444",
  55         "1.2.8888888888888888.33333333333333333.44444444444444",
  56     };
  57 
  58     public static void main(String[] args) throws Exception {
  59         if (args[0].equals("check")) {
  60             int version = Integer.valueOf(System.getProperty("java.version")
  61                     .split("\\.")[1]);
  62             System.out.println("version is " + version);
  63             if (version >= 7) {
  64                 for (String oid: SMALL) {
  65                     // 7 -> 7
  66                     check(out(oid), oid);
  67                     // 6 -> 7
  68                     check(out6(oid), oid);
  69                 }
  70                 for (String oid: HUGE) {
  71                     // 7 -> 7
  72                     check(out(oid), oid);
  73                 }
  74             } else {
  75                 for (String oid: SMALL) {
  76                     // 6 -> 6
  77                     check(out(oid), oid);
  78                     // 7 -> 6
  79                     check(out7(oid), oid);
  80                 }
  81                 for (String oid: HUGE) {
  82                     // 7 -> 6 fails for HUGE oids
  83                     boolean ok = false;
  84                     try {
  85                         check(out7(oid), oid);
  86                         ok = true;
  87                     } catch (Exception e) {
  88                         System.out.println(e);
  89                     }
  90                     if (ok) {
  91                         throw new Exception();
  92                     }
  93                 }
  94             }
  95         } else {
  96             // Generates the JDK6 serialized string inside this test, call
  97             //      $JDK7/bin/java S11N dump7
  98             //      $JDK6/bin/java S11N dump6
  99             // and paste the output at the end of this test.
 100             dump(args[0], SMALL);
 101             // For jdk6, the following line will throw an exception, ignore it
 102             dump(args[0], HUGE);
 103         }
 104     }
 105 
 106     // Gets the serialized form for jdk6
 107     private static byte[] out6(String oid) throws Exception {
 108         return getCoder().decode(dump6.get(oid));
 109     }
 110 
 111     // Gets the serialized form for jdk7
 112     private static byte[] out7(String oid) throws Exception {
 113         return getCoder().decode(dump7.get(oid));
 114     }
 115 
 116     // Gets the serialized form for this java
 117     private static byte[] out(String oid) throws Exception {
 118         ByteArrayOutputStream bout = new ByteArrayOutputStream();
 119         new ObjectOutputStream(bout).writeObject(new ObjectIdentifier(oid));
 120         return bout.toByteArray();
 121     }
 122 
 123     // Makes sure serialized form can be deserialized
 124     private static void check(byte[] in, String oid) throws Exception {
 125         ObjectIdentifier o = (ObjectIdentifier) (
 126                 new ObjectInputStream(new ByteArrayInputStream(in)).readObject());
 127         if (!o.toString().equals(oid)) {
 128             throw new Exception("Read Fail " + o + ", not " + oid);
 129         }
 130     }
 131 
 132     // dump serialized form to java code style text
 133     private static void dump(String title, String[] oids) throws Exception {
 134         for (String oid: oids) {
 135             String base64 = getCoder().encode(out(oid)).replaceAll("\n", "");
 136 
 137             System.out.format("        %s.put(\"%s\",%n            \"", title, oid);
 138             for (int i=0; i<base64.length(); i++) {
 139                 System.out.format("%s", base64.charAt(i));
 140                 if (i == base64.length() - 1)
 141                     System.out.format("\");%n");
 142                 else if (i != 0 && (i+1) % 64 == 0)
 143                     System.out.format("\" +%n            \"");
 144             }
 145         }
 146     }
 147 
 148     // Reflective use of Base64 coders so the test can compile/run on older JDKs
 149     interface Coder {
 150         String encode(byte bytes[]) throws Exception;
 151         byte[] decode(String src) throws Exception;
 152     }
 153 
 154     static Coder getCoder() {
 155         try {
 156             return new JavaUtilBase64Coder();
 157         } catch (ClassNotFoundException x) {
 158             return new SunMiscBase64Coder();
 159         }
 160     }
 161 
 162     static class JavaUtilBase64Coder implements Coder {
 163         final Object encoder, decoder;
 164         final Method encodeMethod, decodeMethod;
 165 
 166         JavaUtilBase64Coder() throws ClassNotFoundException {
 167             Class<?> c = Class.forName("java.util.Base64");
 168             try {
 169                 encoder = c.getDeclaredMethod("getEncoder").invoke(null);
 170                 decoder = c.getDeclaredMethod("getDecoder").invoke(null);
 171                 encodeMethod = Class.forName("java.util.Base64$Encoder")
 172                                     .getDeclaredMethod("encode", byte[].class);
 173                 decodeMethod = Class.forName("java.util.Base64$Decoder")
 174                                     .getDeclaredMethod("decode", String.class);
 175             } catch (Exception x) {
 176                 throw new AssertionError(x);
 177             }
 178         }
 179         public String encode(byte aBuffer[]) throws Exception {
 180             return new String((byte[]) encodeMethod.invoke(encoder, aBuffer));
 181         }
 182         public byte[] decode(String src) throws Exception{
 183             return (byte[]) decodeMethod.invoke(decoder, src);
 184         }
 185     }
 186 
 187     static class SunMiscBase64Coder implements Coder {
 188         final Object encoder, decoder;
 189         final Method encodeMethod, decodeMethod;
 190 
 191         SunMiscBase64Coder()  {
 192             try {
 193                 encoder = Class.forName("sun.misc.BASE64Encoder").newInstance();
 194                 decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
 195                 encodeMethod = encoder.getClass().getMethod("encodeBuffer", byte[].class);
 196                 decodeMethod = decoder.getClass().getMethod("decodeBuffer", String.class);
 197             } catch (Exception x) {
 198                 throw new AssertionError(x);
 199             }
 200         }
 201         public String encode(byte aBuffer[]) throws Exception {
 202             return (String) encodeMethod.invoke(encoder, aBuffer);
 203         }
 204         public byte[] decode(String src) throws Exception {
 205             return (byte[]) decodeMethod.invoke(decoder, src);
 206         }
 207     }
 208 
 209     // Do not use diamond operator, this test is also meant to run in jdk6
 210     private static Map<String,String> dump7 = new HashMap<String,String>();
 211     private static Map<String,String> dump6 = new HashMap<String,String>();
 212 
 213     static {
 214         //////////////  PASTE BEGIN //////////////
 215         dump7.put("0.0",
 216             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 217             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 218             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhwAAAAAnVyAAJbSU26YCZ26rKlAgAAeHAA" +
 219             "AAACAAAAAAAAAAB1cgACW0Ks8xf4BghU4AIAAHhwAAAAAQB4");
 220         dump7.put("1.1",
 221             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 222             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 223             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhwAAAAAnVyAAJbSU26YCZ26rKlAgAAeHAA" +
 224             "AAACAAAAAQAAAAF1cgACW0Ks8xf4BghU4AIAAHhwAAAAASl4");
 225         dump7.put("2.2",
 226             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 227             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 228             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhwAAAAAnVyAAJbSU26YCZ26rKlAgAAeHAA" +
 229             "AAACAAAAAgAAAAJ1cgACW0Ks8xf4BghU4AIAAHhwAAAAAVJ4");
 230         dump7.put("1.2.3456",
 231             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 232             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 233             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhwAAAAA3VyAAJbSU26YCZ26rKlAgAAeHAA" +
 234             "AAADAAAAAQAAAAIAAA2AdXIAAltCrPMX+AYIVOACAAB4cAAAAAMqmwB4");
 235         dump7.put("1.2.2147483647.4",
 236             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 237             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 238             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhwAAAABHVyAAJbSU26YCZ26rKlAgAAeHAA" +
 239             "AAAEAAAAAQAAAAJ/////AAAABHVyAAJbQqzzF/gGCFTgAgAAeHAAAAAHKof///9/" +
 240             "BHg=");
 241         dump7.put("1.2.268435456.4",
 242             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 243             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 244             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhwAAAABHVyAAJbSU26YCZ26rKlAgAAeHAA" +
 245             "AAAEAAAAAQAAAAIQAAAAAAAABHVyAAJbQqzzF/gGCFTgAgAAeHAAAAAHKoGAgIAA" +
 246             "BHg=");
 247         dump7.put("2.16.764.1.3101555394.1.0.100.2.1",
 248             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 249             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 250             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhw/////3NyAD5zdW4uc2VjdXJpdHkudXRp" +
 251             "bC5PYmplY3RJZGVudGlmaWVyJEh1Z2VPaWROb3RTdXBwb3J0ZWRCeU9sZEpESwAA" +
 252             "AAAAAAABAgAAeHB1cgACW0Ks8xf4BghU4AIAAHhwAAAADmCFfAGLxvf1QgEAZAIB" +
 253             "eA==");
 254         dump7.put("1.2.2147483648.4",
 255             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 256             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 257             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhw/////3NyAD5zdW4uc2VjdXJpdHkudXRp" +
 258             "bC5PYmplY3RJZGVudGlmaWVyJEh1Z2VPaWROb3RTdXBwb3J0ZWRCeU9sZEpESwAA" +
 259             "AAAAAAABAgAAeHB1cgACW0Ks8xf4BghU4AIAAHhwAAAAByqIgICAAAR4");
 260         dump7.put("2.3.4444444444444444444444",
 261             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 262             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 263             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhw/////3NyAD5zdW4uc2VjdXJpdHkudXRp" +
 264             "bC5PYmplY3RJZGVudGlmaWVyJEh1Z2VPaWROb3RTdXBwb3J0ZWRCeU9sZEpESwAA" +
 265             "AAAAAAABAgAAeHB1cgACW0Ks8xf4BghU4AIAAHhwAAAADFOD4e+HpNG968eOHHg=");
 266         dump7.put("1.2.8888888888888888.33333333333333333.44444444444444",
 267             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 268             "fy4DAANJAAxjb21wb25lbnRMZW5MAApjb21wb25lbnRzdAASTGphdmEvbGFuZy9P" +
 269             "YmplY3Q7WwAIZW5jb2Rpbmd0AAJbQnhw/////3NyAD5zdW4uc2VjdXJpdHkudXRp" +
 270             "bC5PYmplY3RJZGVudGlmaWVyJEh1Z2VPaWROb3RTdXBwb3J0ZWRCeU9sZEpESwAA" +
 271             "AAAAAAABAgAAeHB1cgACW0Ks8xf4BghU4AIAAHhwAAAAGCqP5Yzbxa6cOLubj9ek" +
 272             "japVio3AusuOHHg=");
 273 
 274         dump6.put("0.0",
 275             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 276             "fy4CAAJJAAxjb21wb25lbnRMZW5bAApjb21wb25lbnRzdAACW0l4cAAAAAJ1cgAC" +
 277             "W0lNumAmduqypQIAAHhwAAAAAgAAAAAAAAAA");
 278         dump6.put("1.1",
 279             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 280             "fy4CAAJJAAxjb21wb25lbnRMZW5bAApjb21wb25lbnRzdAACW0l4cAAAAAJ1cgAC" +
 281             "W0lNumAmduqypQIAAHhwAAAAAgAAAAEAAAAB");
 282         dump6.put("2.2",
 283             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 284             "fy4CAAJJAAxjb21wb25lbnRMZW5bAApjb21wb25lbnRzdAACW0l4cAAAAAJ1cgAC" +
 285             "W0lNumAmduqypQIAAHhwAAAAAgAAAAIAAAAC");
 286         dump6.put("1.2.3456",
 287             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 288             "fy4CAAJJAAxjb21wb25lbnRMZW5bAApjb21wb25lbnRzdAACW0l4cAAAAAN1cgAC" +
 289             "W0lNumAmduqypQIAAHhwAAAAAwAAAAEAAAACAAANgA==");
 290         dump6.put("1.2.2147483647.4",
 291             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 292             "fy4CAAJJAAxjb21wb25lbnRMZW5bAApjb21wb25lbnRzdAACW0l4cAAAAAR1cgAC" +
 293             "W0lNumAmduqypQIAAHhwAAAABAAAAAEAAAACf////wAAAAQ=");
 294         dump6.put("1.2.268435456.4",
 295             "rO0ABXNyACJzdW4uc2VjdXJpdHkudXRpbC5PYmplY3RJZGVudGlmaWVyeLIO7GQX" +
 296             "fy4CAAJJAAxjb21wb25lbnRMZW5bAApjb21wb25lbnRzdAACW0l4cAAAAAR1cgAC" +
 297             "W0lNumAmduqypQIAAHhwAAAABAAAAAEAAAACEAAAAAAAAAQ=");
 298         //////////////  PASTE END //////////////
 299     }
 300 }