1 /* 2 * Copyright (c) 2015, 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 8048357 27 * @summary PKCS8 Standards Conformance Tests 28 * @modules java.base/sun.security.pkcs 29 * java.base/sun.security.util 30 * java.base/sun.security.provider 31 * java.base/sun.security.x509 32 * java.base/sun.misc 33 * @compile -XDignore.symbol.file PKCS8Test.java 34 * @run main PKCS8Test 35 */ 36 import java.io.IOException; 37 import java.math.BigInteger; 38 import java.security.InvalidKeyException; 39 import java.util.Arrays; 40 import sun.misc.HexDumpEncoder; 41 import sun.security.pkcs.PKCS8Key; 42 import sun.security.provider.DSAPrivateKey; 43 import sun.security.util.DerOutputStream; 44 import sun.security.util.DerValue; 45 import sun.security.x509.AlgorithmId; 46 import static java.lang.System.out; 47 48 public class PKCS8Test { 49 50 static final HexDumpEncoder hexDump = new HexDumpEncoder(); 51 52 static final DerOutputStream derOutput = new DerOutputStream(); 53 54 static final String FORMAT = "PKCS#8"; 55 static final String EXPECTED_ALG_ID_CHRS = "DSA\n\tp: 02\n\tq: 03\n" 56 + "\tg: 04\n"; 57 static final String ALGORITHM = "DSA"; 58 static final String EXCEPTION_MESSAGE = "version mismatch: (supported: " 59 + "00, parsed: 01"; 60 61 // test second branch in byte[] encode() 62 // DER encoding,include (empty) set of attributes 63 static final int[] NEW_ENCODED_KEY_INTS = { 0x30, 64 // length 30 = 0x1e 65 0x1e, 66 // first element 67 // version Version (= INTEGER) 68 0x02, 69 // length 1 70 0x01, 71 // value 0 72 0x00, 73 // second element 74 // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier 75 // (sequence) 76 // (an object identifier?) 77 0x30, 78 // length 18 79 0x12, 80 // contents 81 // object identifier, 5 bytes 82 0x06, 0x05, 83 // { 1 3 14 3 2 12 } 84 0x2b, 0x0e, 0x03, 0x02, 0x0c, 85 // sequence, 9 bytes 86 0x30, 0x09, 87 // integer 2 88 0x02, 0x01, 0x02, 89 // integer 3 90 0x02, 0x01, 0x03, 91 // integer 4 92 0x02, 0x01, 0x04, 93 // third element 94 // privateKey PrivateKey (= OCTET STRING) 95 0x04, 96 // length 97 0x03, 98 // privateKey contents 99 0x02, 0x01, 0x01, 100 // 4th (optional) element -- attributes [0] IMPLICIT Attributes 101 // OPTIONAL 102 // (Attributes = SET OF Attribute) Here, it will be empty. 103 0xA0, 104 // length 105 0x00 }; 106 107 // encoding originally created, but with the version changed 108 static final int[] NEW_ENCODED_KEY_INTS_2 = { 109 // sequence 110 0x30, 111 // length 28 = 0x1c 112 0x1c, 113 // first element 114 // version Version (= INTEGER) 115 0x02, 116 // length 1 117 0x01, 118 // value 1 (illegal) 119 0x01, 120 // second element 121 // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier 122 // (sequence) 123 // (an object identifier?) 124 0x30, 125 // length 18 126 0x12, 127 // contents 128 // object identifier, 5 bytes 129 0x06, 0x05, 130 // { 1 3 14 3 2 12 } 131 0x2b, 0x0e, 0x03, 0x02, 0x0c, 132 // sequence, 9 bytes 133 0x30, 0x09, 134 // integer 2 135 0x02, 0x01, 0x02, 136 // integer 3 137 0x02, 0x01, 0x03, 138 // integer 4 139 0x02, 0x01, 0x04, 140 // third element 141 // privateKey PrivateKey (= OCTET STRING) 142 0x04, 143 // length 144 0x03, 145 // privateKey contents 146 0x02, 0x01, 0x01 }; 147 148 // 0000: 30 1E 02 01 00 30 14 06 07 2A 86 48 CE 38 04 01 0....0...*.H.8.. 149 // 0010: 30 09 02 01 02 02 01 03 02 01 04 04 03 02 01 01 0............... 150 static final int[] EXPECTED = { 0x30, 151 // length 30 = 0x1e 152 0x1e, 153 // first element 154 // version Version (= INTEGER) 155 0x02, 156 // length 1 157 0x01, 158 // value 0 159 0x00, 160 // second element 161 // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier 162 // (sequence) 163 // (an object identifier?) 164 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01, 165 // integer 2 166 0x30, 0x09, 0x02, 167 // integer 3 168 0x01, 0x02, 0x02, 169 // integer 4 170 0x01, 0x03, 0x02, 171 // third element 172 // privateKey PrivateKey (= OCTET STRING) 173 0x01, 174 // length 175 0x04, 176 // privateKey contents 177 0x04, 0x03, 0x02, 178 // 4th (optional) element -- attributes [0] IMPLICIT Attributes 179 // OPTIONAL 180 // (Attributes = SET OF Attribute) Here, it will be empty. 181 0x01, 182 // length 183 0x01 }; 184 185 static void raiseException(String expected, String received) { 186 throw new RuntimeException( 187 "Expected " + expected + "; Received " + received); 188 } 189 190 public static void main(String[] args) 191 throws IOException, InvalidKeyException { 192 193 BigInteger p = BigInteger.valueOf(1); 194 BigInteger q = BigInteger.valueOf(2); 195 BigInteger g = BigInteger.valueOf(3); 196 BigInteger x = BigInteger.valueOf(4); 197 198 DSAPrivateKey priv = new DSAPrivateKey(p, q, g, x); 199 200 byte[] encodedKey = priv.getEncoded(); 201 byte[] expectedBytes = new byte[EXPECTED.length]; 202 for (int i = 0; i < EXPECTED.length; i++) { 203 expectedBytes[i] = (byte) EXPECTED[i]; 204 } 205 206 dumpByteArray("encodedKey :", encodedKey); 207 if (!Arrays.equals(encodedKey, expectedBytes)) { 208 raiseException(new String(expectedBytes), new String(encodedKey)); 209 } 210 211 // skip Solaris since the DSAPrivateKeys returned by SunPKCS11 Provider 212 // are not a subclasses of PKCS8Key 213 if (!System.getProperty("os.name").equalsIgnoreCase("sunos")) { 214 PKCS8Key decodedKey = PKCS8Key.parse(new DerValue(encodedKey)); 215 216 String alg = decodedKey.getAlgorithm(); 217 AlgorithmId algId = decodedKey.getAlgorithmId(); 218 out.println("Algorithm :" + alg); 219 out.println("AlgorithmId: " + algId); 220 221 if (!ALGORITHM.equals(alg)) { 222 raiseException(ALGORITHM, alg); 223 } 224 if (!EXPECTED_ALG_ID_CHRS.equalsIgnoreCase(algId.toString())) { 225 raiseException(EXPECTED_ALG_ID_CHRS, algId.toString()); 226 } 227 228 decodedKey.encode(derOutput); 229 dumpByteArray("Stream encode: ", derOutput.toByteArray()); 230 if (!Arrays.equals(derOutput.toByteArray(), expectedBytes)) { 231 raiseException(new String(expectedBytes), derOutput.toString()); 232 } 233 234 dumpByteArray("byte[] encoding: ", decodedKey.getEncoded()); 235 if (!Arrays.equals(decodedKey.getEncoded(), expectedBytes)) { 236 raiseException(new String(expectedBytes), 237 new String(decodedKey.getEncoded())); 238 } 239 240 if (!FORMAT.equals(decodedKey.getFormat())) { 241 raiseException(FORMAT, decodedKey.getFormat()); 242 } 243 244 try { 245 byte[] newEncodedKey = new byte[NEW_ENCODED_KEY_INTS.length]; 246 for (int i = 0; i < newEncodedKey.length; i++) { 247 newEncodedKey[i] = (byte) NEW_ENCODED_KEY_INTS[i]; 248 } 249 PKCS8Key newDecodedKey = PKCS8Key 250 .parse(new DerValue(newEncodedKey)); 251 252 throw new RuntimeException( 253 "key1: Expected an IOException during " + "parsing"); 254 } catch (IOException e) { 255 System.out.println( 256 "newEncodedKey: should have excess data due to " 257 + "attributes, which are not supported"); 258 } 259 260 try { 261 byte[] newEncodedKey2 = new byte[NEW_ENCODED_KEY_INTS_2.length]; 262 for (int i = 0; i < newEncodedKey2.length; i++) { 263 newEncodedKey2[i] = (byte) NEW_ENCODED_KEY_INTS_2[i]; 264 } 265 266 PKCS8Key newDecodedKey2 = PKCS8Key 267 .parse(new DerValue(newEncodedKey2)); 268 269 throw new RuntimeException( 270 "key2: Expected an IOException during " + "parsing"); 271 } catch (IOException e) { 272 out.println("Key 2: should be illegal version"); 273 out.println(e.getMessage()); 274 if (!EXCEPTION_MESSAGE.equals(e.getMessage())) { 275 throw new RuntimeException("Key2: expected: " 276 + EXCEPTION_MESSAGE + " get: " + e.getMessage()); 277 } 278 } 279 } 280 281 } 282 283 static void dumpByteArray(String nm, byte[] bytes) throws IOException { 284 out.println(nm + " length: " + bytes.length); 285 hexDump.encodeBuffer(bytes, out); 286 } 287 }