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