/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.test.lib.security; import jdk.test.lib.Asserts; import sun.security.util.DerInputStream; import sun.security.util.DerValue; import sun.security.util.ObjectIdentifier; import java.io.IOException; public class DerUtils { /** * Returns a DerValue (deep) inside another DerValue. *

* The location of the inner DerValue is expressed as a string, in which * each character is a step from the outer DerValue into the inner one. * If it's a number n, the n'th element (starting from 0) of a sequence * is the next step. If it's 'c', the content of an OctetString parsed * as a DerValue is the next step. Note that n cannot be bigger than 9. *

* Attention: do not reuse the return value. DerValue is mutable and * reading it advances a pointer inside. *

* For example, here is a PKCS #12 file: *

     * 0000:0845  [] SEQUENCE
     * 0004:0003  [0]     INTEGER 3
     * 0007:07FE  [1]     SEQUENCE
     * 000B:000B  [10]         OID 1.2.840.113549.1.7.1 (data)
     * 0016:07EF  [11]         cont [0]
     * 001A:07EB  [110]             OCTET STRING
     * ...
     * 
* and the content of OCTET string at offset 001A can be parsed as another * DerValue which is: *
     * 0000:07E7  [] SEQUENCE
     * 0004:0303  [0]     SEQUENCE
     * 0008:000B  [00]         OID 1.2.840.113549.1.7.1 (data)
     * ....
     * 
* Then the OID is {@code innerDerValue(data, "110c00").getOID()}. * * @param data the outer DerValue. We choose byte[] instead of DerValue * because DerValue is mutable and cannot be reused. * @param location the location of the inner DerValue * @return the inner DerValue, or null if no DerValue is at the location * @throws IOException if an I/O error happens */ public static DerValue innerDerValue(byte[] data, String location) throws IOException { DerValue v = new DerValue(data); for (char step : location.toCharArray()) { if (step == 'c') { v = new DerValue(v.getOctetString()); } else { DerInputStream ins = v.getData(); // skip n DerValue in the sequence for (int i = 0; i < step - '0'; i++) { ins.getDerValue(); } if (ins.available() > 0) { v = ins.getDerValue(); } else { return null; } } } return v; } /** * Ensures that the inner DerValue is the expected ObjectIdentifier. */ public static void checkAlg(byte[] der, String location, ObjectIdentifier expected) throws Exception { Asserts.assertEQ(innerDerValue(der, location).getOID(), expected); } /** * Ensures that the inner DerValue is the expected integer. */ public static void checkInt(byte[] der, String location, int expected) throws Exception { Asserts.assertEQ(innerDerValue(der, location).getInteger(), expected); } /** * Ensures that there is no inner DerValue at the specified location. */ public static void shouldNotExist(byte[] der, String location) throws Exception { Asserts.assertTrue(innerDerValue(der, location) == null); } }