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