1 /* 2 * Copyright (c) 2018, 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 package jdk.test.lib.security; 24 25 import jdk.test.lib.Asserts; 26 import sun.security.util.DerInputStream; 27 import sun.security.util.DerValue; 28 import sun.security.util.ObjectIdentifier; 29 30 import java.io.IOException; 31 32 public class DerUtils { 33 /** 34 * Returns a DerValue (deep) inside another DerValue. 35 * <p> 36 * The location of the inner DerValue is expressed as a string, in which 37 * each character is a step from the outer DerValue into the inner one. 38 * If it's a number n, the n'th element (starting from 0) of a sequence 39 * is the next step. If it's 'c', the content of an OctetString parsed 40 * as a DerValue is the next step. Note that n cannot be bigger than 9. 41 * <p> 42 * Attention: do not reuse the return value. DerValue is mutable and 43 * reading it advances a pointer inside. 44 * <p> 45 * For example, here is a PKCS #12 file: 46 * <pre> 47 * 0000:0845 [] SEQUENCE 48 * 0004:0003 [0] INTEGER 3 49 * 0007:07FE [1] SEQUENCE 50 * 000B:000B [10] OID 1.2.840.113549.1.7.1 (data) 51 * 0016:07EF [11] cont [0] 52 * 001A:07EB [110] OCTET STRING 53 * ... 54 * </pre> 55 * and the content of OCTET string at offset 001A can be parsed as another 56 * DerValue which is: 57 * <pre> 58 * 0000:07E7 [] SEQUENCE 59 * 0004:0303 [0] SEQUENCE 60 * 0008:000B [00] OID 1.2.840.113549.1.7.1 (data) 61 * .... 62 * </pre> 63 * Then the OID is {@code innerDerValue(data, "110c00").getOID()}. 64 * 65 * @param data the outer DerValue. We choose byte[] instead of DerValue 66 * because DerValue is mutable and cannot be reused. 67 * @param location the location of the inner DerValue 68 * @return the inner DerValue, or null if no DerValue is at the location 69 * @throws IOException if an I/O error happens 70 */ 71 public static DerValue innerDerValue(byte[] data, String location) 72 throws IOException { 73 74 DerValue v = new DerValue(data); 75 for (char step : location.toCharArray()) { 76 if (step == 'c') { 77 v = new DerValue(v.getOctetString()); 78 } else { 79 DerInputStream ins = v.getData(); 80 // skip n DerValue in the sequence 81 for (int i = 0; i < step - '0'; i++) { 82 ins.getDerValue(); 83 } 84 if (ins.available() > 0) { 85 v = ins.getDerValue(); 86 } else { 87 return null; 88 } 89 } 90 } 91 return v; 92 } 93 94 /** 95 * Ensures that the inner DerValue is the expected ObjectIdentifier. 96 */ 97 public static void checkAlg(byte[] der, String location, 98 ObjectIdentifier expected) throws Exception { 99 Asserts.assertEQ(innerDerValue(der, location).getOID(), expected); 100 } 101 102 /** 103 * Ensures that the inner DerValue is the expected integer. 104 */ 105 public static void checkInt(byte[] der, String location, int expected) 106 throws Exception { 107 Asserts.assertEQ(innerDerValue(der, location).getInteger(), expected); 108 } 109 110 /** 111 * Ensures that there is no inner DerValue at the specified location. 112 */ 113 public static void shouldNotExist(byte[] der, String location) 114 throws Exception { 115 Asserts.assertTrue(innerDerValue(der, location) == null); 116 } 117 }