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